我如何在 Rust 中将结构方法作为回调传递?

How can i pass a struct method as callback in Rust?

在 C++ 中,我使用这个。

class A{
    public:
        void read();
}

class B{
    public:
    void setCallback(std::function<void()> f){
        ...
    }
}

int main(){
    A a;
    B b;
    b.setCallback(std::bind(&A::read,&a));
}

我可以在 Rust 中实现相同的功能吗?

这对你有用吗?

struct A {
    x: u32,
}

impl A {
    fn do_something(&mut self) {
        self.x += 1;
    }
}

struct B<F> {
    callback: Option<F>,
}

impl<F: FnMut()> B<F> {
    fn set_callback(&mut self, callback: F) {
        self.callback = Some(callback);
    }
    
    fn call_callback(&mut self) {
        self.callback.as_mut().map(|cb| cb());
    }
}

fn main() {
    let mut a = A { x: 0, };
    let mut b = B { callback: None, };
    b.set_callback(|| a.do_something());
    b.call_callback();
    assert_eq!(a.x, 1);
}

我保守地猜测了可变性要求是什么。

@isaactfa 的回答是正确的,但是 std::function 使用动态调度并且更像 Box<dyn Fn()> 而不是使用泛型。

struct B<'a> {
    callback: Option<Box<dyn FnMut() + 'a>>,
}

impl<'a> B<'a> {
    fn set_callback(&mut self, callback: Box<dyn FnMut() + 'a>) {
        self.callback = Some(callback);
    }

    fn call_callback(&mut self) {
        self.callback.as_mut().map(|cb| cb());
    }
}

fn main() {
    let mut a = A { x: 0 };
    let mut b = B { callback: None };
    b.set_callback(Box::new(|| a.do_something()));
    b.call_callback();
    drop(b); // It is necessary for the code to not use `a` while it's borrowed by the closure
    assert_eq!(a.x, 1);
}

Playground.

您可以通过在结构方法中创建 Box 来获得更多便利,因此调用者不必创建它:

impl<'a> B<'a> {
    fn set_callback(&mut self, callback: impl FnMut() + 'a) {
        self.callback = Some(Box::new(callback));
    }
}

Playground.