I have the following code I have some compilation problems with.
pub trait ATrait {
async fn afunc(&self, x: u32) -> u32;
}
struct ATraitWrapper<T: ATrait + Send + Clone + 'static> {
inner: T,
}
impl<T: ATrait + Send + Clone + 'static> ATrait for ATraitWrapper<T> {
async fn afunc(&self, x: u32) -> u32 {
let (tx, rx) = std::sync::mpsc::channel();
let inner_clone = self.inner.clone();
tokio::spawn(async move {
let result = inner_clone.afunc(x).await;
tx.send(result).expect("Failed to send through channel")
});
rx.recv().expect("Failed to receive from channel")
}
}
pub struct MyStruct {
value: u32,
}
impl ATrait for MyStruct {
async fn afunc(&self, x: u32) -> u32 {
self.value + x
}
}
The error I get is on tokio::spawn:
error: future cannot be sent between threads safely
--> src/lib.rs:11:9
|
11 | tokio::spawn(async move {
| ^^^^^^^^^^^^ future created by async block is not `Send`
|
= help: within `{async block@src/lib.rs:11:22: 14:10}`, the trait `Send` is not implemented for `impl Future<Output = u32>`
note: future is not `Send` as it awaits another future which is not `Send`
--> src/lib.rs:12:26
|
12 | let result = inner_clone.afunc(x).await;
| ^^^^^^^^^^^^^^^^^^^^ await occurs here on type `impl Future<Output = u32>`, which is not `Send`
note: required by a bound in `tokio::spawn`
--> /playground/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.36.0/src/task/spawn.rs:166:21
|
164 | pub fn spawn<F>(future: F) -> JoinHandle<F::Output>
| ----- required by a bound in this function
165 | where
166 | F: Future + Send + 'static,
| ^^^^ required by this bound in `spawn`
help: `Send` can be made part of the associated future's guarantees for all implementations of `ATrait::afunc`
|
2 - async fn afunc(&self, x: u32) -> u32;
2 + fn afunc(&self, x: u32) -> impl std::future::Future<Output = u32> + Send;
|
The type of the closure is Future<Output=()>, why can't it be Send?
The problem is, that one can write valid implementations of
ATraitthat do not produce aSendfuture fromafuncfor example:and your code being generic has to work for every possible implementation (even nonsensical ones like my example).
The compiler aready suggests a fix for this, that disallows such definitions use
as your method signature instead.