I want the async block in the following code to implement Send
(Playground):
use std::collections::BTreeSet;
use std::future::ready;
pub fn test<T: Sync>(set: &BTreeSet<T>) -> impl Send + '_ {
async move {
for _ in set {
ready(()).await;
}
}
}
But it gives the following error:
Compiling playground v0.0.1 (/playground)
error[E0311]: the parameter type `T` may not live long enough
--> src/lib.rs:4:44
|
4 | pub fn test<T: Sync>(set: &BTreeSet<T>) -> impl Send + '_ {
| -- ^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
| |
| help: consider adding an explicit lifetime bound...: `T: 'a +`
error: aborting due to previous error
error: could not compile `playground`
To learn more, run the command again with --verbose.
I don't understand the error at all. Adding a lifetime bound does not solve the problem (Playground), unless the added lifetime bound is 'static
(Playground).
I tried replacing BTreeSet
with Vec
, VecDeque
, LinkedList
, HashSet
, BinaryHeap
. All compiled without error. What is so special about BTreeSet
?
It appears that the error is a bug in Rust -- async
functions are fairly new and it seems that there are a number of issues with odd or incorrect compiler errors, particularly with generics. I think this may be issue #71058 or maybe issue #64552.
I find that often lifetime errors like this, just mean the compiler is saying "Help! I'm confused."
Here's an example of a gratuitous change, which I think is functionally the same:
use std::collections::BTreeSet;
use std::future::ready;
type ItemType = dyn Sync;
pub fn test<ItemType>(set: &BTreeSet<ItemType>) -> impl Send + '_ {
async move {
for _ in set {
ready(()).await;
}
}
}
which produces an error which I think is closer to what is tripping up the compiler (but still incorrect) Playground:
error: future cannot be sent between threads safely
--> src/lib.rs:6:52
|
6 | pub fn test<ItemType>(set: &BTreeSet<ItemType>) -> impl Send + '_ {
| ^^^^^^^^^^^^^^ future created by async block is not `Send`
|
note: captured value is not `Send`
--> src/lib.rs:8:18
|
8 | for _ in set {
| ^^^ has type `&BTreeSet<ItemType>` which is not `Send`
help: consider restricting type parameter `ItemType`
|
6 | pub fn test<ItemType: std::marker::Sync>(set: &BTreeSet<ItemType>) -> impl Send + '_ {
| ^^^^^^^^^^^^^^^^^^^
The above Rust error says that the future is not Send
which would be the case if the async closure captured a data structure that did not support Send
. In this case, it captures BTreeSet which does support Send.
Why this happens with BTreeSet
and not Vec
or one of the other data structures you mention is likely some tiny difference in the syntax of its implementation that is tripping up the compiler.
You created a nice minimal example, so not sure what you are trying to accomplish. Here's a workaround that might help:
use std::collections::BTreeSet;
use std::future::ready;
use std::vec::Vec;
use futures::future::join_all;
pub async fn test<T: Sync>(set: &BTreeSet<T>) -> impl Send + '_ {
let mut future_list = Vec::new();
for _ in set {
let new_future = async move {
ready(()).await;
};
future_list.push(new_future);
};
join_all(future_list).await
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With