pub struct TestAlloc {
func: Box<dyn FnMut()>,
}
impl TestAlloc {
pub fn new(sf: impl FnMut() + 'static) -> Self {
TestAlloc {
func: Box::new(sf),
}
}
pub fn call_func(&mut self) {
println!("invoking callback");
(self.func)();
}
pub fn map(mut self) -> Self {
TestAlloc::new(
move || {
println!("In callback 2");
let _local: i32 = 1; // allocated on stack at the invocation point than moved to heap within new()?
self.call_func(); // stack allocated self moved here
}
)
}
}
fn main() {
let mut t = TestAlloc::new(|| println!("In callback 1"));
let mut wrapped_t = t.map();
wrapped_t.call_func();
}
So new() function takes closure and puts it on the heap. map() method takes ownership of self and returns new TestAlloc object with the owned self moved into closure which is moved to heap after.
My guess is that variable _local is first allocated on stack than moved to heap when callback is boxed?
In the map() moved self is originally allocated on the stack, when moved into callback that is moved to heap, is: a)self also moved to heap meaning completely copied from one memory address to new one and heap allocated callback holds pointer to different heap allocation containing self? b) heap allocated callback holds owned pointer to stack allocated self, no copying? c)self moved to heap as a part of the callback, it is in the same memory block with _local? d) something else?
It's d): self is moved to heap as a part of the callback (referred more idiomatically as "closure"), but _local is never moved to heap. As you have guessed, _local is allocated on the stack (ignoring dead code elimination for now), but this allocation is only done when the closure is actually called. TestAlloc::new moves the closure into the heap, but all of this happens beforewrapped_t.call_func(); is called.
More generally speaking, a piece of code within a closure is not invoked when the closure is created. If you were parsing the code's control flow from its syntactic structure, this might have confused you. If that was the case, you should revisit your mental model of the inherent way closures work.
That was my rookie confusion yes, _local is always on stack (when closure is invoked), I got confused by invoking closure being on the heap.
While the initial stack allocated self is moved right away on the heap as soon map is called?