我如何克服这样的事情:
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 */ }
答案 0 :(得分:3)
你在这里尝试做的是获取一个函数指针(在这里使用Python术语,因为Rust没有 这个词)绑定方法。你不能。
首先,因为Rust没有&#34; bound&#34;方法;也就是说,你不能引用一个方法,其中调用者(.
左侧的东西)已经绑定到位。如果你想构造一个近似于它的callable,你可以使用一个闭包; 即 || self.a()
。
然而,这个仍然不起作用,因为闭包不是函数指针。没有&#34;基本类型&#34;适用于其他语言的可调用内容。函数指针是一种特定的可调用类型;封闭是完全不同的。相反,有些特征(在实现时)使类型可调用。它们是Fn
,FnMut
和FnOnce
。因为它们是特征,所以您不能将它们用作类型,而必须在某些间接层后面使用它们,例如Box<FnOnce()>
或&mut FnMut(i32) -> String
。
现在,您可以更改Test
来存储Option<Box<Fn()>>
,但这仍然无济于事。这是因为另一个其他问题:您正试图在其内部存储对结构的引用。这不运行良好。如果您设法执行此操作,则会有效地使Test
值永久无法使用。更有可能的是,编译器只是不让你走得那么远。
除了:你可以做到这一点,但不是没有借助于引用计数和动态借用检查,这超出了范围。
所以问题的答案是:你不是。
让我们改变一个问题:我们可以改为存储一个不会试图捕获调用者的可调用者,而不是试图撬开自我引用的闭包。
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
。
除了:我还更正了您的
Test::new
功能。 Rust没有构造函数,只是返回值的函数。
如果您确信自己永远不想在foo
中存储关闭,则可以将Box<Fn(&Test)>
替换为fn(&Test)
。这限制了你的函数指针,但避免了额外的分配。
如果您还没有,我强烈敦促您阅读the Rust Book。
答案 1 :(得分:2)
您的代码几乎没有错误。新功能(按惯例)不应该自我引用,因为它应该创建自我类型。
但真正的问题是,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
}