I have the following code:
fn test() -> (impl FnMut(&mut u8), impl FnMut(&mut u8)) {
let a = |v: &mut u8| {*v = 0};
let b = move |v: &mut u8| { a(v); println!("{}", v) };
(a, b)
}
fn main() {
let mut val: u8 = 10;
let (mut a, mut b) = test();
b(&mut val);
val = 10;
a(&mut val);
assert!(val == 0);
}
(this is a MWE based on something I encountered in the wild). Now, this works as expected, but I don't really understand why this even compiles: We need to move a
into b
to use it there (otherwise, one gets a compiler error), but somehow, we can still return a
afterwards and use it without any issue. Doesn't this go against the basic principles of the borrow checker? What is going on here?
The one explanation I could imagine is that the actual a
closure somehow gets coerced to a function pointer with a static lifetime, and it is just this pointer that is being moved (i.e. copied) into the b
closure. However, I have no way to verify this.
Closures will automatically implement Copy
if they are able (reference). The closure for a
is trivially copyable since it does not capture anything. And when you move something that implements Copy
, the original is still usable which is why a
can be both moved into b
as well as returned.