将方法作为回调函数发送到 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 生命周期。

当我在 processcallback 方法中将 &'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 被移出FooFoo 被销毁时,此引用将无效。解决此问题的一种(天真的)方法是使用 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 将确保 footimercallback 每个都足够长,因为它们在 [=26] 中创建和销毁的顺序=].