[英]Using !Send object on async function works, but does not work on trait function
Suppose we have a type that is not Send.假设我们有一个不是 Send 的类型。
struct NotSend { field: std::rc::Rc<i32> }
Then, following async function can still take NotSend as its parameter and compiles well:然后,按照 async function 仍然可以将 NotSend 作为其参数并且编译良好:
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.但是当我在特征内部定义相同的 function 时,任何实现它的东西都不会编译。
#[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?与天真的 function 和 function 有什么不同? Why one does works but not the other?
为什么一个有效,而另一个无效? Playground Link
游乐场链接
It's because async_trait
expands to something like Pin<Box<dyn Future>>
.这是因为
async_trait
扩展为Pin<Box<dyn Future>>
之类的东西。 If we want the resulting future to be Send
, it needs to be Pin<Box<dyn Future>> + Send
.如果我们希望得到的未来是
Send
,它需要是Pin<Box<dyn Future>> + Send
。 But this forces it to be Send
, ie will error on non- Send
futures.但这会强制它为
Send
,即在非Send
期货上会出错。 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. async_trait
crate 没有办法知道未来是否是Send
(因为 trait 的实现与其声明不同,我们需要在声明站点决定未来是否为Send
),所以它选择使用用户定义的注释。
By default, the generated type is Send
since most futures needs to be Send
.默认情况下,生成的类型是
Send
因为大多数期货需要是Send
。 However, as explained in the documentation , you can use #[async_trait(?Send)]
to opt this out:但是, 如文档中所述,您可以使用
#[async_trait(?Send)]
来选择退出:
#[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 } }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.