如何从 Rust 中的特征获取函数指针?
How do I get a function pointer from a trait in Rust?
我该如何克服这样的事情:
struct Test {
foo: Option<fn()>
}
impl Test {
fn new(&mut self) {
self.foo = Option::Some(self.a);
}
fn a(&self) { /* can use Test */ }
}
我收到这个错误:
error: attempted to take value of method `a` on type `&mut Test`
--> src/main.rs:7:36
|
7 | self.foo = Option::Some(self.a);
| ^
|
= help: maybe a `()` to call it is missing? If not, try an anonymous function
如何从特征传递函数指针?类似于这种情况下发生的情况:
impl Test {
fn new(&mut self) {
self.foo = Option::Some(a);
}
}
fn a() { /* can't use Test */ }
您的代码几乎没有错误。新函数(按照惯例)不应该使用 self 引用,因为它应该创建 Self 类型。
但真正的问题是,Test::foo
需要一个函数类型 fn()
,但是 Test::a
的类型是 fn(&Test)
== fn a(&self)
如果你将 foo
的类型更改为 fn(&Test)
它将起作用。您还需要使用带有特征名称的函数名称而不是 self
。而不是分配给 self.a
你应该分配 Test::a
.
这是工作版本:
extern crate chrono;
struct Test {
foo: Option<fn(&Test)>
}
impl Test {
fn new() -> Test {
Test {
foo: Some(Test::a)
}
}
fn a(&self) {
println!("a run!");
}
}
fn main() {
let test = Test::new();
test.foo.unwrap()(&test);
}
此外,如果您要在 new()
函数中分配一个字段,并且该值必须始终设置,则无需使用 Option
而是可以像这样:
extern crate chrono;
struct Test {
foo: fn(&Test)
}
impl Test {
fn new() -> Test {
Test {
foo: Test::a
}
}
fn a(&self) {
println!("a run!");
}
}
fn main() {
let test = Test::new();
(test.foo)(&test); // Make sure the paranthesis are there
}
你在这里试图做的是从一个函数指针(这里使用 Python 术语,因为 Rust 没有 有 一个词this) 绑定方法。你不能。
首先,因为 Rust 没有 "bound" 方法的概念;也就是说,您不能引用已经绑定到位的调用者(.
左侧的东西)的方法。如果您想构造一个近似于此的可调用对象,则可以使用闭包; 即 || self.a()
.
然而,这个仍然不会起作用,因为闭包不是函数指针。没有 "base type" 用于可调用的东西,就像在其他一些语言中一样。函数指针是一种单一的、特定的可调用对象;闭包是完全不同的。相反,有些特征(在实现时)使类型可调用。它们是 Fn
、FnMut
和 FnOnce
。因为它们是特征,所以不能将它们用作类型,而必须从某个间接层后面使用它们,例如 Box<FnOnce()>
或 &mut FnMut(i32) -> String
.
现在,您 可以 更改 Test
来存储 Option<Box<Fn()>>
,但这仍然无济于事。那是因为另一个 other 问题:您试图在自身内部存储对结构的引用。这 不会 会很好地工作。如果你设法做到这一点,你实际上使 Test
值永久无法使用。更有可能的是编译器不会让你走那么远。
Aside: you can do it, but not without resorting to reference counting and dynamic borrow checking, which is out of scope here.
所以你的问题的答案是:你不知道。
让我们改变一下问题:我们可以存储一个根本不会尝试捕获调用者的可调用对象,而不是试图撬开一个自引用闭包。
struct Test {
foo: Option<Box<Fn(&Test)>>,
}
impl Test {
fn new() -> Test {
Test {
foo: Option::Some(Box::new(Self::a)),
}
}
fn a(&self) { /* can use Test */ }
fn invoke(&self) {
if let Some(f) = self.foo.as_ref() {
f(self);
}
}
}
fn main() {
let t = Test::new();
t.invoke();
}
被存储的可调用对象现在是一个显式接受调用者的函数,回避了循环引用的问题。我们可以使用它来直接存储 Test::a
,方法是将其作为自由函数引用。另请注意,因为 Test
是实现类型,所以我也可以将其称为 Self
.
Aside: I've also corrected your Test::new
function. Rust doesn't have constructors, just functions that return values like any other.
如果您确信永远不想在 foo
中存储闭包,则可以将 Box<Fn(&Test)>
替换为 fn(&Test)
。这将您限制为函数指针,但避免了额外的分配。
如果您还没有阅读,我强烈 强烈建议您阅读the Rust Book。
我该如何克服这样的事情:
struct Test {
foo: Option<fn()>
}
impl Test {
fn new(&mut self) {
self.foo = Option::Some(self.a);
}
fn a(&self) { /* can use Test */ }
}
我收到这个错误:
error: attempted to take value of method `a` on type `&mut Test`
--> src/main.rs:7:36
|
7 | self.foo = Option::Some(self.a);
| ^
|
= help: maybe a `()` to call it is missing? If not, try an anonymous function
如何从特征传递函数指针?类似于这种情况下发生的情况:
impl Test {
fn new(&mut self) {
self.foo = Option::Some(a);
}
}
fn a() { /* can't use Test */ }
您的代码几乎没有错误。新函数(按照惯例)不应该使用 self 引用,因为它应该创建 Self 类型。
但真正的问题是,Test::foo
需要一个函数类型 fn()
,但是 Test::a
的类型是 fn(&Test)
== fn a(&self)
如果你将 foo
的类型更改为 fn(&Test)
它将起作用。您还需要使用带有特征名称的函数名称而不是 self
。而不是分配给 self.a
你应该分配 Test::a
.
这是工作版本:
extern crate chrono;
struct Test {
foo: Option<fn(&Test)>
}
impl Test {
fn new() -> Test {
Test {
foo: Some(Test::a)
}
}
fn a(&self) {
println!("a run!");
}
}
fn main() {
let test = Test::new();
test.foo.unwrap()(&test);
}
此外,如果您要在 new()
函数中分配一个字段,并且该值必须始终设置,则无需使用 Option
而是可以像这样:
extern crate chrono;
struct Test {
foo: fn(&Test)
}
impl Test {
fn new() -> Test {
Test {
foo: Test::a
}
}
fn a(&self) {
println!("a run!");
}
}
fn main() {
let test = Test::new();
(test.foo)(&test); // Make sure the paranthesis are there
}
你在这里试图做的是从一个函数指针(这里使用 Python 术语,因为 Rust 没有 有 一个词this) 绑定方法。你不能。
首先,因为 Rust 没有 "bound" 方法的概念;也就是说,您不能引用已经绑定到位的调用者(.
左侧的东西)的方法。如果您想构造一个近似于此的可调用对象,则可以使用闭包; 即 || self.a()
.
然而,这个仍然不会起作用,因为闭包不是函数指针。没有 "base type" 用于可调用的东西,就像在其他一些语言中一样。函数指针是一种单一的、特定的可调用对象;闭包是完全不同的。相反,有些特征(在实现时)使类型可调用。它们是 Fn
、FnMut
和 FnOnce
。因为它们是特征,所以不能将它们用作类型,而必须从某个间接层后面使用它们,例如 Box<FnOnce()>
或 &mut FnMut(i32) -> String
.
现在,您 可以 更改 Test
来存储 Option<Box<Fn()>>
,但这仍然无济于事。那是因为另一个 other 问题:您试图在自身内部存储对结构的引用。这 不会 会很好地工作。如果你设法做到这一点,你实际上使 Test
值永久无法使用。更有可能的是编译器不会让你走那么远。
Aside: you can do it, but not without resorting to reference counting and dynamic borrow checking, which is out of scope here.
所以你的问题的答案是:你不知道。
让我们改变一下问题:我们可以存储一个根本不会尝试捕获调用者的可调用对象,而不是试图撬开一个自引用闭包。
struct Test {
foo: Option<Box<Fn(&Test)>>,
}
impl Test {
fn new() -> Test {
Test {
foo: Option::Some(Box::new(Self::a)),
}
}
fn a(&self) { /* can use Test */ }
fn invoke(&self) {
if let Some(f) = self.foo.as_ref() {
f(self);
}
}
}
fn main() {
let t = Test::new();
t.invoke();
}
被存储的可调用对象现在是一个显式接受调用者的函数,回避了循环引用的问题。我们可以使用它来直接存储 Test::a
,方法是将其作为自由函数引用。另请注意,因为 Test
是实现类型,所以我也可以将其称为 Self
.
Aside: I've also corrected your
Test::new
function. Rust doesn't have constructors, just functions that return values like any other.
如果您确信永远不想在 foo
中存储闭包,则可以将 Box<Fn(&Test)>
替换为 fn(&Test)
。这将您限制为函数指针,但避免了额外的分配。
如果您还没有阅读,我强烈 强烈建议您阅读the Rust Book。