如何在结构上存储回调列表?

时间:2015-03-12 04:03:58

标签: rust

这是我对how to create & use a list of callbacks的问题的跟进。

我试图创建(并在事件循环附近存储)一个回调函数列表,这些函数将在未来的某个不确定点调用。

struct ComplexThing {
    calls: Vec<Box<FnMut()>>,
}


impl ComplexThing {
    fn call<'a, T: FnMut() + 'a>(&'a mut self, func: T) {
        self.calls.push(Box::new(func));
    }
}

错误:

calls.rs:30:25: 30:39 error: the parameter type `T` may not live long enough [E0310]
calls.rs:30         self.calls.push(Box::new(func));
                                    ^~~~~~~~~~~~~~
calls.rs:30:39: 30:39 help: consider adding an explicit lifetime bound `T: 'static`...
calls.rs:30:25: 30:39 note: ...so that the type `T` will meet its required lifetime bounds
calls.rs:30         self.calls.push(Box::new(func));
                                    ^~~~~~~~~~~~~~

我尝试将其添加到struct,修正了push调用中有关生命周期的错误,

struct ComplexThing<'a> {
    calls: Vec<Box<FnMut() + 'a>>,
}


impl ComplexThing {
    fn call<'a, T: FnMut() + 'a>(&'a mut self, func: T) {
        self.calls.push(Box::new(func));
    }
}

......但是得到了我:

calls.rs:28:6: 28:18 error: wrong number of lifetime parameters: expected 1, found 0 [E0107]
calls.rs:28 impl ComplexThing {
                 ^~~~~~~~~~~~

哪,是的,我认为结构有一个<'a>,而我没有指定它。如果我添加它,

impl ComplexThing<'a> {

我明白了,

calls.rs:28:19: 28:21 error: use of undeclared lifetime name `'a` [E0261]
calls.rs:28 impl ComplexThing<'a> {

我不知道我是否应该在struct ComplexThing上指定它。如果我把它关掉(我想我会更喜欢),

我认为有关Rust如何记录我未能到达的生命周期的事情至关重要。 FnMut {目前}试图存储在ComplexThing中的Box是(在我的脑海中的设计中){em>拥有的实例{{1} }};它的生命周期应该小于ComplexThing的生命周期 - 即,会发生以下两种情况之一:

  1. .ComplexThing的私有函数将最终从ComplexThing移除Box<FnMut>(因此取得其所有权),运行Vec ,然后退出,从而释放FnMut
  2. FnMut已取消分配,在这种情况下,ComplexThing和任何Vec已取消分配。
  3. 问题"How do I store a closure in Rust?"的答案让我觉得Box<FnMut>不需要终身注释,但我得到的答案how to create & use a list of callbacks让我觉得我做了

    我最好的猜测是Box<FnMut>只是存储指向我并不真正拥有的对象的指针,我需要在堆上创建Box的副本,或者在那里构建一个,然后该副本就是我可以拥有的副本。 (否则,如果它像堆栈上的闭包那样,我需要确保在FnMut之前闭包没有超出范围,这就是为什么Rust让我注释生命。)

1 个答案:

答案 0 :(得分:3)

'a上的{p> ComplexThing是一个通用的生命周期参数,需要定义与泛型类型参数一样多。如果您有struct Foo<T>,则无法编写impl Foo<T>,因为范围内没有具体类型T;如果您希望它是通用的,则需要定义它impl<T> Foo<T>。这也允许您编写约束,例如impl<T: Clone> Foo<T>,只有在Foo<T>是实现T的类型的情况下才能在Clone上实现方法。

那么,答案很简单,你需要将生命周期'a定义为通用:

impl<'a> ComplexThing<'a> { … }