简体   繁体   English

使用,在异步上发送 object function 可以工作,但不能在 trait function 上工作

[英]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.

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