You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何非Send类型在普通async函数可用,在trait的async函数中不可用?

普通async函数与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 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


核心差异分析

两者表现不同的关键在于**#[async_trait]的默认行为会强制要求返回的Future实现Send,而普通async函数的Send约束是编译器自动推导的**:

  • 普通async函数:编译器会根据函数内部捕获的变量,自动判断返回的Future是否满足Send trait。即使参数是非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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 19:15:51