Hello,
I'm trying to understand how to define the lifetime bounds of a rust function that takes an "async closure" (a normal closure that returns a future). I can get my ideal syntax working with actual async closures on nightly, but no luck replicating this on stable.
pub async fn repeat_new<F, Fut, T>(&mut self, mut cb: F) -> T
where
// Seems to be the crux
for<'a> F: FnMut(&'a mut Ctx) -> Fut + 'a,
Fut: Future<Output = Loop<T>> + Send,
{
loop {
let mut branch = self.clone();
match cb(&mut branch).await {
Loop::Continue => {}
Loop::Break(v) => break v,
}
branch.ack().await;
}
}
// Works great
pub async fn repeat_nightly<F, T>(&mut self, mut cb: F) -> T
where
F: AsyncFnMut(&mut Ctx) -> Loop<T>,
{
loop {
let mut branch = self.clone();
match cb(&mut branch).await {
Loop::Continue => {}
Loop::Break(v) => break v,
}
branch.ack().await;
}
}
Full example: Rust Playground
I am by no means an expert in lifetimes, and I've sunken countless hours into this problem trying various tricks from other posts.
I believe the issue lies in that the lifetime of the future should match that of the closure, but adding such a bound forces the branch
variable's lifetime to upgrade as well. This is problematic because branch
should not have live for the entire repeat_new
function body. This causes rust to throw an error stating that branch
is dropped while still borrowed.
I am aware that using Box::pin
can be used to circumvent this issue entirely but I chose not to use it for the following reasons:
Box::pin
andasync
blocks pollute the code and reduce readability.- With pinned futures, you're often forced to clone all of the external data going into the closure for the sole reason of appeasing the compiler. Async closures don't have this problem because they handle the lifetimes of external data correctly.
This post seems to tackle a similar issue and I wonder if the solution comment (can't link because of the 2 link limit on new users, you'll have to scroll down) might be applicable here, but I have no idea how to go about doing that.
Thanks all