How to match an async function with non-static parameter in rust?

We can match a normal function with non-static parameter like this:

fn processor(data: &i32) -> &i32 {
    data
}

fn process<'b>(data: &'b i32, processor: impl 'static + for<'a> Fn(&'a i32) -> &'a i32) -> &'b i32 {
    processor(data)
}

fn main() {
    let data = 1;
    println!("data: {}", process(&data, processor));
}

However, in the async version, as async functions return anonymous future, we cannot indicate that "lifetime of anonymous future is the same with parameter".

use std::future::Future;

async fn processor(data: &i32) -> &i32 {
    data
}

async fn process<'b, F>(data: &'b i32, processor: impl 'static + Fn(&i32) -> F) -> &'b i32 
where F: 'b + Future<Output=&'b i32>
{
    processor(data).await
}

async fn _main() {
    let data = 1;
    println!("data: {}", process(&data, processor).await);
}

Compiler will complain:

error[E0271]: type mismatch resolving `for<'r> <for<'_> fn(&i32) -> impl std::future::Future {processor} as std::ops::FnOnce<(&'r i32,)>>::Output == _`
  --> src/lib.rs:15:26
   |
7  | async fn process<'b, F>(data: &'b i32, processor: impl 'static + Fn(&i32) -> F) -> &'b i32 
   |          -------                                                             - required by this bound in `process`
...
15 |     println!("data: {}", process(&data, processor).await);
   |                          ^^^^^^^ expected bound lifetime parameter, found concrete lifetime

How can I match it?

In general, if you spawn an async task, there is no way to tell how long it will take to complete, so it has to be 'static. However if you enclose it in an async block with the owned data, an inner future that is just being awaited can use references. Playground.

So your problem looks another degree more complicated, maybe you should be able to spawn _main because that owns data.

I will copy your code in the playground and have a look.

Ok, as far as the future is concerned, the valid lifetime will be the one of the reference it will hold, so, tied to self.

So to specify Future::Output as having a lifetime tied to self, you would need Generic Associated Types.

If you want to pursue this, I would advice experimenting a bit with GAT on a nightly compiler with a manually implemented future instead of an async fn. It's easier to visualize what's involved when manually implementing a future instead of using the async keyword.

Use the -> impl Future<> way of writing async functions instead:

fn process<'b, F>(
    data: &'b i32,
    processor: impl Fn(&'b i32) -> F + 'b
) -> impl Future<Output = &'b i32> + 'b
    where F: Future<Output=&'b i32> + 'b
{
    async move { processor(data).await }
}
1 Like

This answer works,but how to do it in trait? Question

Well, I got the answer

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.