I have such a scene:
Call a generic async
function, then use its result to call another function, all using a same parameter &mut context
.
Here is an example:
use futures::Future;
fn tester<F, Fut>(step1: F) where F: Fn(&mut u8) -> Fut { // Here Fut should be a future, don't matter
let mut i: u8 = 0;
step1(&mut i);
step2(&mut i);
// In real code it's:
// step1(reference).await.step2(reference);
}
// A and B are actually same.
async fn step1_A(_: &mut u8) {}
fn step1_B<'a>(_: &'a mut u8) -> impl Future<Output=()> + 'a {
async move {}
}
fn step2(_: &mut u8) {}
fn main() {
let step1_C = |_: &mut u8| async move { };
tester(step1_A);
tester(step1_B);
tester(step1_C);
}
Here step1_A
and step1_B
don't compile, because
mismatched types
expected associated type `<for<'_> fn(&mut u8) -> impl for<'_> futures::Future {step1_A} as FnOnce<(&mut u8,)>>::Output`
found associated type `<for<'_> fn(&mut u8) -> impl for<'_> futures::Future {step1_A} as FnOnce<(&mut u8,)>>::Output`
the required lifetime does not necessarily outlive the empty lifetime
Compiler can't infer correct lifetime, so I should point It out:
// Using HRTB don't work, error is the same
fn tester<F, Fut>(step1: F) where for <'a> F: Fn(&'a mut u8) -> Fut + 'a
Setting lifetime as function generic parameter works:
fn tester<'a, F, Fut>(step1: F) where F: Fn(&'a mut u8) -> Fut
But now calling step2
don't compile, because 'a
is a uncontrolled lifetime, step1 may keep the i
and don't return, and even live longer than i
lives.
I think the lifetime is quite clean here: the context
(i: u8
here) should be rent by step1,get a future, consume that future, return a value, meantime return the controller of the context
, and rent context
to step2.
Writing a closure can make them all compile, but I want to know if there is a way to make fn
case works?