Hello!
I'm trying to understand what the compiler is telling me. I have the following program:
use std::cell::RefCell;
use std::collections::HashMap;
use std::future::Future;
#[derive(Default)]
struct IntMut(RefCell<HashMap<u32, u32>>);
impl IntMut {
async fn async_test(&self) { }
}
async fn my_async() {
let im = IntMut::default();
im.async_test().await;
}
fn do_stuff<T: Future + Send + 'static>(stuff: T) { }
fn main() {
do_stuff(my_async())
}
which gives me:
17 | fn do_stuff<T: Future + Send + 'static>(stuff: T) { }
| -------- ---- required by this bound in `do_stuff`
...
20 | do_stuff(my_async())
| ^^^^^^^^ `std::cell::RefCell<std::collections::HashMap<u32, u32>>` cannot be shared between threads safely
|
= help: within `IntMut`, the trait `std::marker::Sync` is not implemented for `std::cell::RefCell<std::collections::HashMap<u32, u32>>`
= note: required because it appears within the type `IntMut`
= note: required because of the requirements on the impl of `std::marker::Send` for `&IntMut`
= note: required because it appears within the type `for<'r, 's, 't0> {IntMut, &'r IntMut, IntMut, impl std::future::Future, impl std::future::Future, ()}`
= note: required because it appears within the type `[static generator@src/main.rs:12:21: 15:2 for<'r, 's, 't0> {IntMut, &'r IntMut, IntMut, impl std::future::Future, impl std::future::Future, ()}]`
= note: required because it appears within the type `std::future::GenFuture<[static generator@src/main.rs:12:21: 15:2 for<'r, 's, 't0> {IntMut, &'r IntMut, IntMut, impl std::future::Future, impl std::future::Future, ()}]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `impl std::future::Future`
By itself, IntMut
is Send
. If I do not include the call to im.async_test().await
in my_async
then the future returned by my_async
is indeed Send
and the compiler is happy.
It's only when I do the await
that I get this error. My reading of the error is that the generator created by the await
call ends up storing a reference to IntMut
, and &IntMut
is not Send
, so therefore the future is not Send
.
Is that right?
Two follow up questions:
- Is this a real problem or is this a case of the compiler being too conservative? I didn't create an
&IntMut
explicitly and I don't have access to it, so I don't see how it could be shared by multiple threads simultaneously? - Is there any workaround other than, say, using
Mutex
instead ofRefCell
, despite the fact that this struct will never be access simultaneously by multiple threads?