签名相同的两个不同异步函数返回的Future如何存入同一个Vec?
问题原因
- Rust的
async fn返回值是编译器生成的独有不透明类型(对应语法层面的impl Future),哪怕两个异步函数的参数、返回值签名完全一致,只要是不同位置定义的async fn,它们返回的Future类型本质就是完全不同的独立类型。 - Vec要求所有元素是相同类型,Rust没有默认对不同的Future做自动trait对象转换,因此直接push两个不同的Future到Vec会触发类型不匹配错误,编译器提示的
distinct uses of impl Trait result in different opaque types就是对这个规则的说明。
解决方案
最常用的方案是将两个Future都转为动态分派的Future trait对象,通过装箱固定内存布局,统一类型:
- 首先导入必要的依赖:
use std::future::Future; use std::pin::Pin;
- 修改Vec的类型声明,指定元素为装箱的Future trait对象,同时将每个
resolve调用的返回值用Box::pin包装后再push:
// 显式指定Vec元素类型:Pin<Box<dyn Future<Output = 原async函数返回类型>>> let mut futures: Vec<Pin<Box<dyn Future<Output = Result<String, Box<dyn std::error::Error>>>>>> = Vec::new(); for i in 0..self.settings.count { futures.push( Box::pin(crate1::resolve( &self.settings.filed1, &self.settings.filed2, &product.id, )) ); futures.push( Box::pin(crate2::resolve( &self.settings.filed1, &self.settings.filed2, &product.id, )) ); }
如果你的项目引入了futures库,可以用BoxFuture别名简化类型声明:
use futures::future::BoxFuture; // 类型声明简化为如下形式,'_ 是生命周期自动推导标记 let mut futures: Vec<BoxFuture<'_, Result<String, Box<dyn std::error::Error>>>> = Vec::new(); // push逻辑保持不变,依然用Box::pin包装Future
注意:如果后续编译报生命周期相关错误,说明你传入
resolve的引用生命周期短于Future的存活时长,可以将参数改为持有所有权的String而非引用传入,即可消除生命周期约束。
内容的提问来源于stack exchange,提问作者USA LOVER
相关产品推荐
相关产品推荐

