I have the following problem:
- I have a function
foo
that expects a functionf
as argument - The function
f
is async and takes one argument by reference
How do I resolve the lifetimes?
It's easy if f
is async and takes one argument by value, like so:
use std::future::Future;
async fn foo<F, Fut>(f: F)
where
F: 'static + FnOnce(String) -> Fut + Send,
Fut: 'static + Future<Output = String> + Send,
{
let s = "foo".to_string();
let r = f(s).await;
println!("{r}");
}
async fn bar(s: String) -> String {
println!("{s}");
"bar".to_string()
}
#[tokio::main]
async fn main() {
foo(bar).await;
}
foo
bar
It also works fine if s
is a reference, but f
is not an async function:
async fn foo<F>(f: F)
where
F: 'static + FnOnce(&String) -> String + Send,
{
let s = "foo".to_string();
let r = f(&s);
println!("{r}");
}
fn bar(s: &String) -> String {
println!("{s}");
"bar".to_string()
}
#[tokio::main]
async fn main() {
foo(bar).await;
}
foo
bar
But how do I modify so f
takes s
by reference and is an async function? I tried but get an error, I'm sure I'm missing a lifetime annotation somewhere: (I know &String
makes no sense, this is just for demonstration purposes)
use std::future::Future;
async fn foo<F, Fut>(f: F)
where
F: 'static + FnOnce(&String) -> Fut + Send,
Fut: 'static + Future<Output = String> + Send,
{
let s = "foo".to_string();
let r = f(&s).await;
println!("{r}");
}
async fn bar(s: &String) -> String {
println!("{s}");
"bar".to_string()
}
#[tokio::main]
async fn main() {
foo(bar).await;
}
error[E0308]: mismatched types
--> src/main.rs:20:5
|
20 | foo(bar).await;
| ^^^^^^^^ one type is more general than the other
|
= note: expected opaque type `impl for<'a> Future<Output = String>`
found opaque type `impl Future<Output = String>`
= help: consider `await`ing on both `Future`s
= note: distinct uses of `impl Trait` result in different opaque types
note: the lifetime requirement is introduced here
--> src/main.rs:5:37
|
5 | F: 'static + FnOnce(&String) -> Fut + Send,
| ^^^
error: implementation of `FnOnce` is not general enough
--> src/main.rs:20:5
|
3 | / async fn foo<F, Fut>(f: F)
4 | | where
5 | | F: 'static + FnOnce(&String) -> Fut + Send,
| | ---------------------- doesn't satisfy where-clause
6 | | Fut: 'static + Future<Output = String> + Send,
| |__________________________________________________- due to a where-clause on `foo`...
...
20 | foo(bar).await;
| ^^^^^^^^
|
= note: ...`for<'a> fn(&'a String) -> impl Future<Output = String> {bar}` must implement `FnOnce<(&String,)>`
= note: ...but it actually implements `FnOnce<(&'0 String,)>`, for some specific lifetime `'0`
error: implementation of `FnOnce` is not general enough
--> src/main.rs:20:14
|
3 | / async fn foo<F, Fut>(f: F)
4 | | where
5 | | F: 'static + FnOnce(&String) -> Fut + Send,
| | ---------------------- doesn't satisfy where-clause
6 | | Fut: 'static + Future<Output = String> + Send,
| |__________________________________________________- due to a where-clause on `foo`...
...
20 | foo(bar).await;
| ^^^^^
|
= note: ...`for<'a> fn(&'a String) -> impl Future<Output = String> {bar}` must implement `FnOnce<(&String,)>`
= note: ...but it actually implements `FnOnce<(&'0 String,)>`, for some specific lifetime `'0`
Source: View source