Could you help me with the lifetime issue with returning a future of future from an async method?

⚓ Rust    📅 2025-04-27    👤 surdeus    👁️ 4      

surdeus

Warning

This post was published 116 days ago. The information described in this article may have changed.

Context:

I want to release a lock after the first stage of a feature is completed. So I made a method that returns a future of a future. The idea is that I can hold the lock when await the outer future, release the lock after the outer future resolves, then await the inner future.

However, I'm not able to drop the lock guard while the inner future is alive. Because the inner future's lifetime is forced to be coupled with &self. But I don't see why the inner future needs to have its lifetime tied to &self. Could you help me out? Thanks a lot.

Here's the code example with inline questions.

use std::{marker::PhantomData, pin::Pin};

use futures::FutureExt;

struct MyType<T>(PhantomData<T>);

impl<T> MyType<T> {
    async fn get(
        &self,
        fut: impl Future<Output = T> + 'static,
    ) -> Pin<Box<dyn Future<Output = T> + '_>> {
        let ret = fut.await;
        // Without `'_` above, the compiler will complain that:
        // the parameter type `T` may not live long enough
        // the parameter type `T` must be valid for the static lifetime...
        //
        // But adding `'_` means the returned future cannot live longer than `self`.
        // Why is this necessary? Doesn't the future only refer to `ret`, which has nothing to do
        // with `self` once it's computed?
        async { ret }.boxed_local()
    }
}

async fn example() {
    let my_type = MyType::<i32>(PhantomData);
    let intermediate = my_type.get(async { 42 }).await;
    // The following line will not compile because `intermediate`'s lifetime is tied to `my_type`.
    // But ideally, I want to decouple the lifetime of `intermediate` from `my_type`.
    drop(my_type);
    println!("Result: {}", intermediate.await);
}

1 post - 1 participant

Read full topic

🏷️ rust_feed