Why can't async block borrow from borrowed arguments of parent closure

This simple closure doesn't compile:

|i: &i32| async move { i; true };
error: lifetime may not live long enough
 --> src/main.rs:2:16
  |
2 |      |i: &i32| async move { i; true };
  |          -   - ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
  |          |   |
  |          |   return type of closure `impl Future` contains a lifetime `'2`
  |          let's call the lifetime of this reference `'1`

While this function does compile:

async fn f(i: &i32) -> bool {
    i; true
}

What is the difference between the two? Why closure type is inferred as for<'1, '2> &'1 i32 -> impl Future + '2, while the async fn type is infered to be for<'1> &'1 i32 -> impl Future + '1?

P.S.: I know that I can copy i before async block, but it's just an MRE of the problem
P.P.S.: This came out while trying to make async guard fns work, a more real-life example in this playground.

Because they are not same.

Modified function:

fn f(i: &i32) -> impl std::future::Future<Output = bool> + '_ {
    async { i; true }
}

In your first code you have closure and have async block. Async block is capture i variable, that why there are error.

It is not async block fault. Same error with closure:

fn f(i: &i32) -> impl Fn() -> bool + '_ {
    || { i; true }
}

If you'll add move to your example, it will work too, so I don't think your explanation is right:

fn f(i: &i32) -> impl std::future::Future<Output = bool> + '_ {
    async move { i; true }
}

(your example didn't work b/c async block borrowed i, so it had &'2 &i32 where '2 is a lifetime local to the function)

1 Like
|i: &i32| move || { i; true };

Not working too. Looks like lifetime inference problem. Maybe this related.

1 Like