You'll need to either make it a Box<dyn FnMut()>
, or store a plain fn()
, or make it generic. FnMut
allows closures with varying amounts of capture data, so different closures implementing FnMut
are different sizes. You can fix this by doing one of the following:
-
Allow different sized FnMut
s: change dyn FnMut()
to Box<dyn FnMut()>
This works because the Box
will make separate allocations for each one, and then also store a vtable to differentiate between them
-
Don't allow captured variables at all: change dyn FnMut()
to fn()
fn()
with a lowercase f
is the type for a literal function pointer. This won't allow closures which capture variables, but that comes with the advantage of being able to store everything as a simple pointer to the function
-
Restrict to a specific type of closure: make Defers
generic over T: FnMut()
. This would fix the problem of different closures having different size by simply saying "each Defers
can only store a specific closure". Since you're adding to it in a loop (and thus only add from one closure definition), this should work for this case.
Since this is a bit more involved, I'll include a code snippet - it'd be roughly:
struct Defers<T: FnMut()> {
stack: Vec<T>,
}
impl<T: FnMut()> Defers<T> {
fn Defer(&mut self, F: T) {
self.stack.Push(F);
}
fn New() -> Defers {
Defers { stack: Vec::new() }
}
}
impl<T: FnMut()> Drop for Defers<T> { ...
On top of that, you have one other problem: when calling d.Defers
, you're just putting the function call inside. This will call println!()
immediately, and then pass the result into Defers
- I don't think this is what you want. If I'm understanding correctly, this will do what you intend:
d.Defer(|| println!("{}", x));