5

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.

1 Answer 1

7

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.