简体   繁体   中英

Using !Send object on async function works, but does not work on trait function

Suppose we have a type that is not Send.

 struct NotSend { field: std::rc::Rc<i32> }

Then, following async function can still take NotSend as its parameter and compiles well:

 async fn func(not_send: NotSend) -> i32 { 0 }

But when I define the same function inside of the trait, then anything that implements it does not compile.

 #[async_trait] trait A { async fn func(not_send: NotSend) -> i32; } struct S { } #[async_trait] impl A for S { async fn func(not_send: NotSend) -> i32 { 0 } }

This fails with the following message:

 error: future cannot be sent between threads safely --> src/main.rs:23:46 | 23 | async fn func( not_send: NotSend) -> i32 { | ______________________________________________^ 24 | | 0 25 | | } | |_____^ future created by async block is not `Send` | = help: within `impl Future<Output = i32>`, the trait `Send` is not implemented for `Rc<i32>` note: captured value is not `Send` --> src/main.rs:23:20 | 23 | async fn func( not_send: NotSend) -> i32 { | ^^^^^^^^ has type `NotSend` which is not `Send` = note: required for the cast to the object type `dyn Future<Output = i32> + Send`

What's so different from the naive function and the function in the trait? Why one does works but not the other? Playground Link

It's because async_trait expands to something like Pin<Box<dyn Future>> . If we want the resulting future to be Send , it needs to be Pin<Box<dyn Future>> + Send . But this forces it to be Send , ie will error on non- Send futures. The async_trait crate does not have a way to know whether the future is Send (because the implementation of the trait is different from its declaration, and we need to decide at declaration site whether the future will be Send or not), so it opts to use user-defined annotations.

By default, the generated type is Send since most futures needs to be Send . However, as explained in the documentation , you can use #[async_trait(?Send)] to opt this out:

 #[async_trait(?Send)] trait A { async fn func(not_send: NotSend) -> i32; } struct S { } #[async_trait(?Send)] impl A for S { async fn func(not_send: NotSend) -> i32 { 0 } }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM