我如何从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 */ }

您要在此处尝试做的是从a获得函数指针(在这里使用python术语,因为Rust没有一个字(绑定方法。你不能。

首先,因为生锈没有"绑定"方法的概念;也就是说,您无法参考已绑定到适当的Invicant(.左侧的事物(的方法。如果要构建一个近似此的可可,则使用闭合;即。 || self.a()

但是,此仍然是不起作用的,因为闭合不是函数指针。像其他某些语言中一样,没有类型的"基本类型"。功能指针是一种单一的,特定的可呼叫;关闭完全不同。相反,(实施时(有一个类型可召唤的特征。它们是FnFnMutFnOnce。因为它们是特征,所以您不能将其用作类型,而必须从某个间接层的后面使用它们,例如Box<FnOnce()>&mut FnMut(i32) -> String

现在,您可以更改Test以存储Option<Box<Fn()>>,但这仍然无济于事。那是因为其他问题是其他问题:您正在尝试存储对内部结构的引用。这不是的工作正常。如果您设法执行此操作,则有效地使Test值永久无法使用。更有可能的是编译器不会让您走那么远。

旁边:您 can 做到这一点,但不是不求助于参考计数和动态借用检查,这是在此处不超出范围的。

所以您提出的问题的答案是:您不。

让我们更改一个问题:我们可以存储一个完全没有尝试捕获发票的可召唤的可召唤的,而不是试图自我指出的封闭。

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中,则可以用fn(&Test)代替CC_17。这限制了您运行指针,但避免了额外的分配。

如果您尚未

您的代码几乎没有错误。新功能(按照公约(不应进行自我参考,因为它有望创建自我类型。

但真正的问题是,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
}

最新更新