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
ComplexThing
will end up removing theBox<FnMut>
from theVec
(and thus, take ownership of it), run theFnMut
, and then exit, thus freeing theFnMut
. - The
ComplexThing
is deallocated, in which case theVec
and 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.)