This is a follow-up to my question on how to create & use a list of callbacks.
I'm trying to create (and store, near an event loop) a list of callback functions that will be called at some indeterminate point in the future.
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));
}
}
Errors with:
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));
^~~~~~~~~~~~~~
I tried adding it to the struct, which fixed the error about lifetimes on the call to 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));
}
}
… but gets me:
calls.rs:28:6: 28:18 error: wrong number of lifetime parameters: expected 1, found 0 [E0107]
calls.rs:28 impl ComplexThing {
^~~~~~~~~~~~
Which, yes, I suppose the struct has a <'a>, and I'm not specifying it. If I add it,
impl ComplexThing<'a> {
I get,
calls.rs:28:19: 28:21 error: use of undeclared lifetime name `'a` [E0261]
calls.rs:28 impl ComplexThing<'a> {
I don't know if I should be specifying it on the struct ComplexThing or not. If I leave it off (and I would greatly prefer to, I think),
I think there's something crucial about how Rust notates lifetimes that I'm not getting here. The FnMut that ComplexThing is (presently) trying to store in a Box is (in the design in my head) owned by the instance of ComplexThing; it's lifetime should be less than that of .ComplexThing — i.e., one of two things would happen:
- What will be a private function of the
ComplexThingwill end up removing theBox<FnMut>from theVec(and thus, take ownership of it), run theFnMut, and then exit, thus freeing theFnMut. - The
ComplexThingis deallocated, in which case theVecand anyBox<FnMut>'s are deallocated with it.
The question "How do I store a closure in Rust?"'s answer made me think a Box<FnMut> wouldn't need lifetime annotations, but the answer I got on how to create & use a list of callbacks makes me think I do.
My best guess is that Box is just storing a pointer to an object that I don't really own, and that I need to either create a copy of the FnMut on the heap, or move-construct one there, and then that copy is the one I can own. (Otherwise, if it's like a closure that's on the stack, I need to make sure that closure doesn't go out of scope before my Box does, which is why Rust is having me annotate lifetimes.)