There is no way to annotate an async fn to not capture a lifetime in it, and inferring that would go against Rust's current philosophy that function signature's should be able to be relied on independently of the body (other than auto-trait leakage in RPIT).
You can instead make bar a normal fn returning an impl Future and use an async block to define it:
The body of an async block is basically identical to the body of an async fn (and you can see the latter as a desugaring to the former), you should be able to write it exactly the same as you would an async fn and just move the code inside the block.
At some places, the branch conditions are self's fields. If I move that condition inside async block, self is captured. If I keep it out of it, I can't write the code without Either.
Async non-move closures are intended to have the same signature lifetime handling of async fn, so are unlikely to help. Current async move |_| { ... } closures are (as far as I'm aware) identical to closures returning async blocks (|_| async move { ... }).
The easiest way to do this is to compute the branch conditions before the block, assign them to bool variables, and then have the async block capture those variables and not self.
Might be too late, but could this be an argument for not stabilizing async functions and instead relying only on async blocks, plus maybe a syntax to capture all lifetimes in the return type, so that the user has to explicitly make this choice? (e.g. fn foo([...]) -> impl Future<[...]> + '* )
Async fn are useful in plenty of situations. I don't see why they should not be stabelized. Note that capturing the lifetime of self is problematic if you want to directly spawn the future on an executor (which usually requires a 'static future.
If you have an async context that owns an object, it can perfectly await methods on that object. Your outer async context will still be 'static and can be spawned.
The future has to capture lifetimes, since it's not run immediately, and the objects need to be around when it does. No different than any other struct that owns references to things.
@withoutboats
Yes thats the approach I am taking now. But it doesnt always feel as natural as writing an regular async fn.
@najamelan
Thing about letting self captured is that some of the code store the future. I ll be propagating lifetime to very large scope.
@bill_myers
I dont think this is reason enough to block stablization of async fns. This problem can probablt solved better with a different design. My question is if something can be done for now. Most codebases doing these things will probably have to redesign around this or use RPIT or custom futures. Tokio already removed some of the poll_* functions in favour of async ones. So users will have to do the same.
Obviously but there's no way around this. You can't use self within the async scope without capturing it, if you don't want to capture it you have to precompute whatever values you need before the async context is constructed. What you are writing is exactly what you want the program to do.