Lifetime in async

It's a series of questions, so bear with me.

async fn not_main() {
    caller(callee, &0).await
}

async fn caller<F: Future<Output = ()>>(f: fn(&i32) -> F, a: &i32) {
    f(a).await
}

async fn callee(_: &i32) {}

this won't compile

After some googling I realized callee didn't satisfy the implicit lifetime requirement so I need to annotate it like this:

async fn not_main() {
    caller(callee, &0).await;
}

async fn caller<'a, F: 'a + Future<Output = ()>>(f: fn(&'a i32) -> F, a: &'a i32) {
    f(a).await;
}

async fn callee(_: &i32) {}

this compiles, but I'm wondering if this is the correct way to handle this?
I also don't get why would I need to specify 'a for a, since a obviously lived long enough? but if I specify another lifetime for a, it won't compile.

anyway at least I got a solution for that.

the next question is, if a is not a parameter of caller, how do I annotate it? since this also won't compile:

async fn not_main() {
    caller(callee).await;
}

async fn caller<'a, F: 'a + Future<Output = ()>>(f: fn(&'a i32) -> F) {
    let a = 0;
    f(&a).await;
}

async fn callee(_: &i32) {}

Thank you for your time.

I found a workaround on SO using trait:

async fn caller(f: impl CalleeTrait) {
    let a = 0;
    f.call(&a).await;
}

trait CalleeTrait {
    async fn call(&self, _: &i32);
}

struct Callee {}

impl CalleeTrait for Callee {
    async fn call(&self, _:&i32) {}
}

While I'm a little surprised this worked, it feels like lots of boilerplate to me. Is there any better patterns?

You can use AsyncFn instead.

fn main() { }

#[allow(dead_code)]
async fn not_main() {
    caller(callee, &0).await;
}

async fn caller(f: impl AsyncFn(&i32), a: &i32) {
    f(a).await;
}

async fn callee(_: &i32) {}
2 Likes

Thanks, didn't even know that existed, guess I should have spent some time on those release notes.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.