问题
In Python or C++, a class say A can delegate some work to another instance of class Say B, and set a callback method of A in B. I try to do this in Rust, but so far I got nowhere, beaten by Rust compiler.
Here is Code I have tried, remaining code is at the end of this post.
In A::test I tried using closure to get a Fn() trait object as callback.
// let b = B::new(self.finish)); // ideally but would not compile
// let test :Box<Fn(String)> = Box::new(move |msg| {self.finish(msg);}); // cannot infer an appropriate lifetime due to conflicting requirements
// let b = B::new(&test);
// let b = B::new(&Box::new( |msg| {A::finish(&self, msg);} )); // expected trait std::ops::Fn, found closure
// let b = B::new(&Box::new( |msg| {self.finish(msg);} )); // expected trait std::ops::Fn, found closure
Nothing work yet. Is there a way doing this?
Any help would be appreciated!
Or Am I fundamentally wrong? Do Rust request an other way to implement the idea here?
Here is my testing code
Play Ground Link
struct A {}
impl A {
fn finish(&self, msg: String) {
println!("{}", msg);
}
fn test(&self) {
//let b = B::new(self.finish)); // would not compile
// let test :Box<Fn(String)> = Box::new(move |msg| {self.finish(msg);}); // cannot infer an appropriate lifetime due to conflicting requirements
// let b = B::new(&test);
// let b = B::new(&Box::new( |msg| {A::finish(&self, msg);} )); // expected trait std::ops::Fn, found closure
let b = B::new(&Box::new( |msg| {self.finish(msg);} )); // expected trait std::ops::Fn, found closure
b.start("hi".to_string().clone());
}
}
struct B<'b> {
// cb:fn(msg:String),
cb: &'b Box<Fn(String)>,
}
impl<'b> B<'b> {
fn new(cb: &'b Box<Fn(String)>) -> B<'b> {
B { cb: cb }
}
fn start(&self, msg: String) {
(self.cb)(msg);
}
}
fn main() {
let a = A {};
a.test();
}
回答1:
Yes you can pass a method as callback to your struct and call it from this struct's method. And you don't need to box the closure as you pass a reference:
struct A {}
impl A {
fn finish(&self, msg: String) {
println!("{}", msg);
}
fn test(&self) {
let fun = |msg: String| self.finish(msg);
let b = B::new(&fun);
b.start("hi".to_string().clone());
}
}
struct B<'b> {
cb: &'b Fn(String),
}
impl<'b> B<'b> {
fn new(cb: &'b Fn(String)) -> B<'b> {
B { cb }
}
fn start(&self, msg: String) {
(self.cb)(msg);
}
}
fn main() {
let a = A {};
a.test();
}
playground
The box is useful when you move your function to the new struct, which is not your case.
Note: As your function is called start, I suspect in your real use case you want to start a thread, in which case you should probably look at channels instead of callbacks.
来源:https://stackoverflow.com/questions/57270635/how-to-pass-a-method-as-callback