Lifetimes issue while storing Rust async closure/functions for later invocation

Hi everyone,

I'm trying to build a small project in Rust to familiarize myself more with the language (and hopefully convince other people at the company I work for to use it ;-) ) and in the past I haven't really touched the async/await features of the language, which are a must for this project/my company's products. The thing that I've gotten stuck on so far is storing async functions or closures to be invoked later.

Here's what I'm playing with so far. I can store an async function without issue, but if I want to apply any sort of adaptation in a closure (even something as simple as doing nothing but awaiting the result and then returning it) I get lifetime issues. I feel like I have a decent handle on lifetimes, and so I'm going to describe my best interpretation of what's going on here with the error message I get, reproduced below for reference. The problem appears to be that there are no guarantees that the closure will outlive its returned Future, and so the associated lifetime with its return type doesn't live long enough. This isn't an issue in the tiny example I have here -- nor is it an actual issue with the places I want to use this pattern --- I would be happy to Box::leak the closure if that somehow worked out, it's a setup thing that will never be removed, but I don't see how to do that. I thought about potentially wrapping everything in yet another Box layer but that didn't seem to work out.

Does anyone have any suggestions? Are there any mistakes in my understanding of the situation, as described here?

Thank you!

The error, for reference

error: lifetime may not live long enough
  --> src/lib.rs:21:31
   |
21 |               Box::new(move |x| Box::new(async {
   |  ______________________--------_^
   | |                      |      |
   | |                      |      return type of closure is Box<(dyn futures::Future<Output = bool> + '2)>
   | |                      lifetime `'1` represents this closure's body
22 | |                 func(x).await
23 | |             }))
   | |______________^ returning this value requires that `'1` must outlive `'2`
   |
       = note: closure implements `Fn`, so references to captured variables can't escape the closure

There are two problems:

  1. You need move to move ownership of x into the returned boxed closure.
  2. You can't give away ownership of func to the returned boxed closure.

You can do this:

self.list.push(
    Box::new(move |x| Box::new(func(x)))
);

or this:

self.list.push(
    Box::new(move |x| {
        let fut = func(x);
        Box::new(async move {
            fut.await
        })
    })
);

Aha! That makes sense, and feels like it's exactly what I was missing.

Thank you very much!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.