I observed the following interesting behavior when combining the commonly used async-trait
crate with anonymous type parameters:
#[async_trait::async_trait]
trait Multicall {
fn messages(&self) -> &[String];
// This doesn't work:
// async fn foo(&self, mut callback: impl FnMut(&str) + Send)
// But we can do:
async fn foo<C: FnMut(&str) + Send>(&self, mut callback: C)
{
for s in self.messages() {
callback(s);
}
}
}
struct S {
messages: Vec<String>,
}
impl Multicall for S {
fn messages(&self) -> &[String] { &self.messages }
}
#[tokio::main]
async fn main() {
let s = S { messages: vec![
"Hello!".to_string(),
"World!".to_string()
] };
s.foo(|x| println!("Say: {}", x)).await;
}
Note there aren't really any lifetime bounds necessary for the reference passed to the closure. But apparently the async_trait
macro will do some "magic" if we use the impl
keyword, resulting in the following error (if we uncomment the signature with impl
):
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:5:19
|
5 | async fn foo(&self, mut callback: impl FnMut(&str) + Send)
| ^^^^
|
note: first, the lifetime cannot outlive the lifetime `'life0` as defined on the method body at 5:14...
--> src/main.rs:5:14
|
5 | async fn foo(&self, mut callback: impl FnMut(&str) + Send)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that the expression is assignable
--> src/main.rs:5:19
|
5 | async fn foo(&self, mut callback: impl FnMut(&str) + Send)
| ^^^^
= note: expected `&Self`
found `&'life0 Self`
note: but, the lifetime must be valid for the lifetime `'life1` as defined on the method body at 5:14...
--> src/main.rs:5:14
|
5 | async fn foo(&self, mut callback: impl FnMut(&str) + Send)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:10:22
|
10 | callback(s);
| ^
I wonder if that is intended, and whether I can/should rely on other the variant using <C: FnMut(&str) + Send>
to keep working in future releases of async-trait
?