为何非Send类型在普通async函数可用,在trait的async函数中不可用?
我们先定义一个非Send类型:
struct NotSend { field: std::rc::Rc<i32> }
普通async函数接收该类型作为参数可正常编译:
async fn func(not_send: NotSend) -> i32 { 0 }
但使用#[async_trait]宏定义的trait中的同名函数,其实现无法编译:
#[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 } }
编译报错信息如下:
error: future cannot be sent between threads safely
--> src/main.rs:23:46
|
async fn func( not_send: NotSend) -> i32 { ______________________________________________^ = help: within
impl Future<Output = i32>, the traitSendis not implemented forRc<i32>
note: captured value is notSend
--> src/main.rs:23:20
|
23 | async fn func( not_send: NotSend) -> i32 {
| ^^^^^^^^ has typeNotSendwhich is notSend
= note: required for the cast to the object typedyn Future<Output = i32> + Send
核心差异分析
两者表现不同的关键在于**#[async_trait]的默认行为会强制要求返回的Future实现Send,而普通async函数的Send约束是编译器自动推导的**:
普通async函数:编译器会根据函数内部捕获的变量,自动判断返回的
Future是否满足Sendtrait。即使参数是非Send类型,只要Future没有被放到需要Send的上下文(比如跨线程任务),编译器不会报错——只会让这个Future不实现Send。#[async_trait]宏:为了适配多线程环境下的 trait 对象使用,宏默认会将 async 方法的返回值包装为dyn Future<Output = ...> + Send。这就要求返回的Future必须实现Send,而你的NotSend类型包含Rc(天生不实现Send),导致生成的Future无法满足约束,因此编译失败。
解决方法
如果不需要在多线程场景下使用这个 trait 对象,可以给#[async_trait]添加?Send标记,取消对Send的强制要求:
#[async_trait(?Send)] trait A { async fn func(not_send: NotSend) -> i32; } #[async_trait(?Send)] impl A for S { async fn func(not_send: NotSend) -> i32 { 0 } }
内容的提问来源于stack exchange,提问作者Jaebum

