Closure that returns captured mutable reference

The following code fails to compile:

fn test<'a>(u: &'a mut u8) -> impl Fn() -> &'a u8 + 'a {
    move || { u }
}

giving the following error:

error[E0313]: lifetime of borrowed pointer outlives lifetime of captured variable `u`...
   --> src/dbus.rs:170:19
    |
170 |         move || { u }
    |                   ^
    |
note: ...the borrowed pointer is valid for the lifetime `'a` as defined on the method body at 169:13...
   --> src/dbus.rs:169:13
    |
169 |     fn test<'a>(u: &'a mut u8) -> impl Fn() -> &'a u8 + 'a {
    |             ^^
note: ...but `u` is only valid for the lifetime `'_` as defined on the body at 170:9
   --> src/dbus.rs:170:9
    |
170 |         move || { u }
    |         ^^^^^^^

If I make the u argument an immutable reference, it works fine. The most I can make of it is that move capturing the reference u changes its lifetime to some anonymous one defined on the closure, but I thought + 'a on the return type would make sure the closure lives long enough. I also don't understand what changes when u is immutable.

This works:

fn test<'a>(u: &'a mut u8) -> impl Fn() -> &'a u8 {
    let u = &*u;
    move || { u }
}

If the closure could have mutable access, it could violate immutability of the returned reference:

fn test<'a>(u: &'a mut u8) -> impl Fn() -> &'a u8 {
    move || { *u += 1; u }
}

fn break() {
    let closure = test(&mut 0);
    let immutable1 = closure();
    assert_eq!(immutable1, 1);
    closure();
    assert_eq!(immutable1, 2); // !?
}
2 Likes

If you need to get a mutable reference back out of the closure, you can use FnOnce so that calling the closure consumes it:

fn test<'a>(u: &'a mut u8) -> impl FnOnce() -> &'a mut u8 {
    move || { *u += 1; u }
}

Thanks, that makes sense. The error message got me thinking down the the wrong track.