Home > Enterprise >  Why am I getting a lifetime mismatch?
Why am I getting a lifetime mismatch?

Time:02-07

The following function compiles without issues:

async fn filter_con<T, O, F>(arr: Vec<T>, predicate: F) -> Vec<T>
where
    O: Future<Output = bool>,
    F: for Fn(&T) -> O,
{
    join_all(arr.into_iter().map(|it| async {
        if predicate(&it).await {
            Some(it)
        } else {
            None
        }
    }))
    .await
    .into_iter()
    .filter_map(|p| p)
    .collect::<Vec<_>>()
}

But I can't find a way to call it properly:

let items_filtered = filter_con(items, filter).await;

Error:

error[E0308]: mismatched types
   --> src/lifecycle/querier.rs:101:30
    |
101 |         let items_filtered = filter_con(items_response, filter).await;
    |                              ^^^^^^^^^^ lifetime mismatch
    |
    = note: expected associated type `<for<'_> fn(&PairInfo) -> impl futures::Future<Output = bool> {lifecycle::querier::filter} as FnOnce<(&PairInfo,)>>::Output`
               found associated type `<for<'_> fn(&PairInfo) -> impl futures::Future<Output = bool> {lifecycle::querier::filter} as FnOnce<(&PairInfo,)>>::Output`
    = note: the required lifetime does not necessarily outlive the empty lifetime
note: the lifetime requirement is introduced here
   --> src/lifecycle/querier.rs:246:26
    |
246 |     F: for<'a> Fn(&T) -> O,
    |                          ^

Why is this happening?


Full playground here

CodePudding user response:

You have essentially the same problem as in here

To make it easier to understand I'll rewrite/desugar some of your code. Let's start with the predicate:

async fn filter(x: &Test) -> bool{
    x.0 >= 50
}

Is functionally equivalent to:

fn filter(x: &Test) -> impl Future<Output=bool>   '_{
    async {
        x.0 >= 50
    }
}

Now it should be obvious that the lifetime of the returned Future is not 'static, but actually it depends on the lifetime of the parameter x: &Test.

This should make the error more understandable - your predicate is returning some future with some lifetime, which is not mentioned anywhere in the generic type definition - you can see that you don't mention it when you define neither O, nor F:

where
    O: Future<Output = bool>,
    F: for Fn(&T) -> O,

The problem is that, currently the language does not provide any means to say that O's lifetime depends on F's lifetime. The only easy solution I know is to use the escape hatch - box the future, which will allow you to use the same lifetime in F and O. the downside is that, F will be heap allocated:

use futures::future::{join_all, Future};
use futures::future::BoxFuture;
use futures::FutureExt;


#[derive(Debug)]
struct Test(usize);

#[tokio::main]
async fn main() {
    let items = vec![Test(10), Test(100), Test(1000)];
    let items_filtered = filter_con(items, filter).await;

    println!("{:?}", items_filtered); // should print [100, 1000]
}

fn filter(x: &Test) -> BoxFuture<'_, bool>{
    async {
        x.0 >= 50
    }.boxed()
}

async fn filter_con<T, F>(arr: Vec<T>, predicate: F) -> Vec<T>
where
    F: for<'a> Fn(&'a T) -> BoxFuture<'a, bool>,
{
    join_all(arr.into_iter().map(|it| async{
        if predicate(&it).await {
            Some(it)
        } else {
            None
        }
    }))
    .await
    .into_iter()
    .filter_map(|p| p)
    .collect::<Vec<_>>()
}

Here is a link to the Rust Plauground

  •  Tags:  
  • Related