async_trait能否搭配动态分发使用?遇Future非Send报错如何解决?
问题原因与差异说明
两者的核心差异来自async_trait宏的默认行为:
- 默认情况下,
async_trait宏会将异步trait方法转换为返回Pin<Box<dyn Future<Output = 对应返回类型> + Send + '_>>的同步方法,强制要求返回的Future实现Sendtrait,以适配多线程异步运行时的跨线程调度需求。 - 独立的异步函数不会被额外添加
Send约束,其返回Future的Send属性是自动推断的,仅当你在需要Send的上下文中调用该函数时才会触发对应的编译检查,单独定义或者在不需要Send的场景下使用不会报错。
你遇到编译报错的直接原因:方法参数&mut dyn Iterator<Item = String>是没有携带Send约束的trait对象,它会被捕获进异步方法生成的Future中,导致Future不满足async_trait默认要求的Send约束,触发编译错误。
解决办法
分两种适配场景选择方案:
场景1:需要Future支持Send(适配多线程异步运行时,比如Tokio多线程Worker)
直接给参数中的dyn Iterator添加Send约束即可,修改后代码如下:
#[async_trait::async_trait] trait StringPrinter { async fn print(a: &mut (dyn Iterator<Item = String> + Send)); } struct MyStringPrinter{} #[async_trait::async_trait] impl StringPrinter for MyStringPrinter { async fn print(a: &mut (dyn Iterator<Item = String> + Send)){ a.for_each(|x| println!("{}", x)); tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; } }
场景2:不需要Future支持Send(仅在单线程异步运行时使用)
给async_trait宏添加?Send参数,关闭默认的Send约束即可,修改后代码如下:
#[async_trait::async_trait(?Send)] trait StringPrinter { async fn print(a: &mut dyn Iterator<Item = String>); } struct MyStringPrinter{} #[async_trait::async_trait(?Send)] impl StringPrinter for MyStringPrinter { async fn print(a: &mut dyn Iterator<Item = String>){ a.for_each(|x| println!("{}", x)); tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; } }
内容的提问来源于stack exchange,提问作者Eyal leshem
相关产品推荐
相关产品推荐

