Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explicit type annotation in closures

Tags:

rust

The following code compiles and executes just fine:

fn b(a: &mut u32) -> &mut u32 {
    let f = || {
        *a = 43;
        a
    };
    f()
}

fn main() {
    let mut a: u32 = 42;
    let r = &mut a;
    b(r);
    println!("{:?}", a);
}

If I now explicitly annotate the closure with let mut f = || -> &mut u32, rust complains:

error: captured variable cannot escape `FnMut` closure body
 --> src/main.rs:4:9
  |
1 | fn b(a: &mut u32) -> &mut u32 {
  |      - variable defined here
2 |     let mut f = || -> &mut u32 {
  |                       - inferred to be a `FnMut` closure
3 |         *a = 43;
  |          - variable captured here
4 |         a
  |         ^ returns a reference to a captured variable which escapes the closure body
  |
  = note: `FnMut` closures only have access to their captured variables while they are executing...
  = note: ...therefore, they cannot allow references to captured variables to escape

I can't make sense of this error.

like image 746
vonaka Avatar asked Dec 06 '25 03:12

vonaka


1 Answers

Closures have complex, subtle, and minimally documented inference rules regarding lifetimes and Fn traits. From the error message, I can tell that adding the return type adds FnMut to this closure's inferred traits, however I don't know why.

If you need to specify the return type, you can fix this by passing the closure through a function that requires FnOnce.

fn b(a: &mut u32) -> &mut u32 {
    let f = make_fn_once(|| -> &mut u32 {
        *a = 43;
        a
    });
    f()
}

fn make_fn_once<F, T>(f: F) -> F
where
    F: FnOnce() -> T,
{
    f
}

Note that even defining the closure and then passing it to the function will not work; it has to be passed directly to the function.

fn b(a: &mut u32) -> &mut u32 {
    // error: captured variable cannot escape `FnMut` closure body
    let f = || -> &mut u32 {
        *a = 43;
        a
    };
    let f = make_fn_once(f);
    f()
}
like image 89
drewtato Avatar answered Dec 08 '25 21:12

drewtato



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!