Rust中async函数是什么类型?如何为dyn trait定义对应方法
Rust中async函数的类型是什么?
现有待补全的代码逻辑如下,目标是持有Box<dyn GenericAsyncRunner>动态分发实例时,可直接调用方法获取Future并await,避免为大量不同Runner实现逐个写向下转型逻辑:
pub trait GenericAsyncRunner{ fn return_run_function(&self) -> ?; } pub enum AsyncRunError{} pub struct SpecificAsyncRunner{} impl SpecificAsyncRunner{ async fn run(&self) -> Result<u32, AsyncRunError> { todo!() } } impl GenericAsyncRunner for SpecificAsyncRunner { fn return_run_function(&self) -> ? { todo!() } }
疑问点:是否可以将async fn run() -> Result<u32, AsyncRunError>改写为返回Future的脱糖版本,拿到具体类型填充代码中?标记的返回值位置?
解答
async fn的脱糖本质
所有async fn都会被编译器脱糖为返回匿名Future类型的普通函数,这个匿名类型由编译器自动生成,实现了Future<Output = 原async fn返回值类型>,没有可在源码中显式写出的类型名,且每个async fn对应的匿名类型都是全局唯一的——不同结构体的run方法即使签名一致,返回的Future类型也完全不同。
你无法直接把这个匿名类型作为trait方法的返回值:如果在trait方法返回位置写impl Future<Output = ...>,会破坏trait的对象安全性,根本无法创建Box<dyn GenericAsyncRunner>这类动态trait对象。
正确实现方式
要支持动态分发的异步trait,必须对返回的Future做类型擦除,使用Pin<Box<dyn Future<Output = T> + 生命周期>>作为统一返回类型,这是Rust生态中异步动态trait的标准实现方案。
补全后的可运行代码如下:
use std::future::Future; use std::pin::Pin; pub trait GenericAsyncRunner{ // ?位置的正确类型 fn return_run_function(&self) -> Pin<Box<dyn Future<Output = Result<u32, AsyncRunError>> + '_>>; } pub enum AsyncRunError{} pub struct SpecificAsyncRunner{} impl SpecificAsyncRunner{ async fn run(&self) -> Result<u32, AsyncRunError> { todo!() } } impl GenericAsyncRunner for SpecificAsyncRunner { fn return_run_function(&self) -> Pin<Box<dyn Future<Output = Result<u32, AsyncRunError>> + '_>> { Box::pin(self.run()) } } // 调用示例 async fn run_task(runner: Box<dyn GenericAsyncRunner>) -> Result<u32, AsyncRunError> { runner.return_run_function().await }
类型细节说明
Box<dyn Future<...>>:将不同实现返回的匿名Future做堆分配,擦除具体类型后统一为动态分发trait对象,解决不同实现返回Future类型不一致的问题Pin包裹:Future在执行过程中可能产生自引用结构,必须通过Pin固定内存地址,才能安全轮询推进执行- 生命周期参数
'_:让返回的Future自动绑定&self的借用生命周期,和原async fn的借用检查规则一致,避免悬垂引用
该方案不需要对任何具体Runner实现做向下转型,所有实现GenericAsyncRunner的类型都可以装入Box<dyn GenericAsyncRunner>直接调用,仅在获取Future时产生一次堆分配开销,await执行过程无额外性能损耗。
内容的提问来源于stack exchange,提问作者Poperton
相关产品推荐
相关产品推荐

