将方法作为回调函数发送到 Rust 中的字段对象
Sending method as callback function to field object in Rust
我想实现一个 Timer
对象,它属于 Foo
对象,它应该定期调用 Foo
对象的方法。我刚刚实现了向 Timer
添加回调函数(正在执行 Foo
对象的方法),如下所示,但由于生命周期要求冲突而无法编译。
代码(不含执行回调函数部分)
use std::sync::Mutex;
#[derive(Default)]
struct Timer<'a> {
callbacks: Mutex<Vec<Box<dyn Fn() + 'a>>>,
}
impl<'a> Timer<'a> {
fn add(&self, callback: Box<dyn Fn() + 'a>) {
let mut callbacks = self.callbacks.lock().unwrap();
callbacks.push(callback);
}
}
#[derive(Default)]
struct Foo<'a> {
value: usize,
timer: Timer<'a>,
}
impl<'a> Foo<'a> {
fn callback(&self) {
println!("value is {}", self.value);
}
fn process(&self) {
let callback = || {
self.callback();
};
self.timer.add(Box::new(callback));
}
}
fn main() {
let foo = Foo::default();
foo.process();
}
编译失败,出现以下错误
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:28:24
|
28 | let callback = || {
| ________________________^
29 | | self.callback();
30 | | };
| |_________^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 27:5...
--> src/main.rs:27:5
|
27 | fn process(&self) {
| ^^^^^^^^^^^^^^^^^
note: ...so that the types are compatible
--> src/main.rs:28:24
|
28 | let callback = || {
| ________________________^
29 | | self.callback();
30 | | };
| |_________^
= note: expected `(&&Foo<'a>,)`
found `(&&Foo<'a>,)`
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 22:6...
--> src/main.rs:22:6
|
22 | impl<'a> Foo<'a> {
| ^^
note: ...so that the types are compatible
--> src/main.rs:32:20
|
32 | self.timer.add(Box::new(callback));
| ^^^
= note: expected `&Timer<'_>`
found `&Timer<'a>`
error: aborting due to previous error
我认为错误来自 Foo
对象中的 process
方法将 self
作为 &'_
生命周期,但 self.timer
需要 &'a
生命周期。
当我在 process
和 callback
方法中将 &'a
生命周期添加到 self
时,
...
impl<'a> Foo<'a> {
fn callback(&'a self) {
...
}
fn process(&'a self) {
...
}
}
...
出现以下错误-
error[E0597]: `self` does not live long enough
--> src/main.rs:29:13
|
22 | impl<'a> Foo<'a> {
| -- lifetime `'a` defined here
...
28 | let callback = || {
| -- value captured here
29 | self.callback();
| ^^^^ borrowed value does not live long enough
...
32 | self.timer.add(Box::new(callback));
| ------------------ cast requires that `self` is borrowed for `'a`
33 | }
| - `self` dropped here while still borrowed
error[E0597]: `foo` does not live long enough
--> src/main.rs:39:5
|
39 | foo.process();
| ^^^ borrowed value does not live long enough
40 | }
| -
| |
| `foo` dropped here while still borrowed
| borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>`
error: aborting due to 2 previous errors
如何解决这个问题?
这里的问题是您想要在 Timer
中创建对 Foo
的引用,但是如果 Foo
被移动或者 Timer
被移出Foo
的 Foo
被销毁时,此引用将无效。解决此问题的一种(天真的)方法是使用 value
的引用计数器并避免直接引用 Foo
:
#[derive(Default)]
struct Foo<'a> {
value: Rc<usize>,
timer: Timer<'a>,
}
impl<'a> Foo<'a> {
fn process(&self) {
let value_rc = self.value.clone();
let callback = move || {
println!("value is {}", *value_rc);
};
self.timer.add(Box::new(callback));
}
}
这使得使用 value
有点困难,并且会在 Rc
中产生运行时开销(如果是多线程,则为 Arc
)。更好的解决方案可能是完全拆分结构并使用像这样的正常生命周期规则:
#[derive(Default)]
struct Foo {
value: usize,
}
impl Foo {
fn callback(&self) {
println!("value is {}", self.value);
}
}
fn main() {
let foo = Foo::default();
let timer = Timer::default();
let callback = || {
foo.callback();
};
timer.add(Box::new(callback));
}
这样,Rust 将确保 foo
、timer
和 callback
每个都足够长,因为它们在 [=26] 中创建和销毁的顺序=].
我想实现一个 Timer
对象,它属于 Foo
对象,它应该定期调用 Foo
对象的方法。我刚刚实现了向 Timer
添加回调函数(正在执行 Foo
对象的方法),如下所示,但由于生命周期要求冲突而无法编译。
代码(不含执行回调函数部分)
use std::sync::Mutex;
#[derive(Default)]
struct Timer<'a> {
callbacks: Mutex<Vec<Box<dyn Fn() + 'a>>>,
}
impl<'a> Timer<'a> {
fn add(&self, callback: Box<dyn Fn() + 'a>) {
let mut callbacks = self.callbacks.lock().unwrap();
callbacks.push(callback);
}
}
#[derive(Default)]
struct Foo<'a> {
value: usize,
timer: Timer<'a>,
}
impl<'a> Foo<'a> {
fn callback(&self) {
println!("value is {}", self.value);
}
fn process(&self) {
let callback = || {
self.callback();
};
self.timer.add(Box::new(callback));
}
}
fn main() {
let foo = Foo::default();
foo.process();
}
编译失败,出现以下错误
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:28:24
|
28 | let callback = || {
| ________________________^
29 | | self.callback();
30 | | };
| |_________^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 27:5...
--> src/main.rs:27:5
|
27 | fn process(&self) {
| ^^^^^^^^^^^^^^^^^
note: ...so that the types are compatible
--> src/main.rs:28:24
|
28 | let callback = || {
| ________________________^
29 | | self.callback();
30 | | };
| |_________^
= note: expected `(&&Foo<'a>,)`
found `(&&Foo<'a>,)`
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 22:6...
--> src/main.rs:22:6
|
22 | impl<'a> Foo<'a> {
| ^^
note: ...so that the types are compatible
--> src/main.rs:32:20
|
32 | self.timer.add(Box::new(callback));
| ^^^
= note: expected `&Timer<'_>`
found `&Timer<'a>`
error: aborting due to previous error
我认为错误来自 Foo
对象中的 process
方法将 self
作为 &'_
生命周期,但 self.timer
需要 &'a
生命周期。
当我在 process
和 callback
方法中将 &'a
生命周期添加到 self
时,
...
impl<'a> Foo<'a> {
fn callback(&'a self) {
...
}
fn process(&'a self) {
...
}
}
...
出现以下错误-
error[E0597]: `self` does not live long enough
--> src/main.rs:29:13
|
22 | impl<'a> Foo<'a> {
| -- lifetime `'a` defined here
...
28 | let callback = || {
| -- value captured here
29 | self.callback();
| ^^^^ borrowed value does not live long enough
...
32 | self.timer.add(Box::new(callback));
| ------------------ cast requires that `self` is borrowed for `'a`
33 | }
| - `self` dropped here while still borrowed
error[E0597]: `foo` does not live long enough
--> src/main.rs:39:5
|
39 | foo.process();
| ^^^ borrowed value does not live long enough
40 | }
| -
| |
| `foo` dropped here while still borrowed
| borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>`
error: aborting due to 2 previous errors
如何解决这个问题?
这里的问题是您想要在 Timer
中创建对 Foo
的引用,但是如果 Foo
被移动或者 Timer
被移出Foo
的 Foo
被销毁时,此引用将无效。解决此问题的一种(天真的)方法是使用 value
的引用计数器并避免直接引用 Foo
:
#[derive(Default)]
struct Foo<'a> {
value: Rc<usize>,
timer: Timer<'a>,
}
impl<'a> Foo<'a> {
fn process(&self) {
let value_rc = self.value.clone();
let callback = move || {
println!("value is {}", *value_rc);
};
self.timer.add(Box::new(callback));
}
}
这使得使用 value
有点困难,并且会在 Rc
中产生运行时开销(如果是多线程,则为 Arc
)。更好的解决方案可能是完全拆分结构并使用像这样的正常生命周期规则:
#[derive(Default)]
struct Foo {
value: usize,
}
impl Foo {
fn callback(&self) {
println!("value is {}", self.value);
}
}
fn main() {
let foo = Foo::default();
let timer = Timer::default();
let callback = || {
foo.callback();
};
timer.add(Box::new(callback));
}
这样,Rust 将确保 foo
、timer
和 callback
每个都足够长,因为它们在 [=26] 中创建和销毁的顺序=].