将异步函数存入结构体时为何需要指定生命周期?
问题:移除Tasks结构体的生命周期
'a后编译失败的原因分析 有一段Rust代码,当保留Tasks结构体的生命周期'a时可以正常编译运行,但移除该生命周期后出现编译错误,具体代码及错误信息如下:
可正常编译的代码
#[derive(Default, Serialize, Deserialize, Debug, Eq, Hash, PartialEq)] pub struct Component { name: String, module: String, r#type: String, url: String, hash: Option<String>, #[serde(skip)] retied_times: i8, } struct Tasks<'a, F> where F: Future<Output = Result<()>>, { foo: fn(&'a str, &'a Component) -> F, } impl<'a, F> Tasks<'a, F> where F: Future<Output = Result<()>>, { pub async fn call(&self, target_dir: &'a str, component: &'a Component) { (self.foo)(target_dir, component).await; } } pub async fn process(target_dir: &str, component: &Component) { let task = Tasks { foo: download }; task.call(target_dir, component); } async fn download(target_dir: &str, component: &Component) -> Result<()> { //... Ok(()) }
移除生命周期'a后的编译错误
--> src/lib.rs:28:29 | 28 | let task = Tasks { foo: download }; | ^^^^^^^^ one type is more general than the other | = note: expected fn pointer `for<'r, 's> fn(&'r str, &'s component::Component) -> _` found fn item `for<'r, 's> fn(&'r str, &'s component::Component) -> impl Future<Output = Result<(), anyhow::Error>> {download}`
原因分析
带
'a生命周期的情况:Tasks<'a, F>中的函数指针类型fn(&'a str, &'a Component) -> F,把两个输入参数的生命周期都绑定到了结构体的'a上。此时编译器可以将download函数的输入生命周期统一约束为'a,它返回的Future类型也会固定为和'a绑定的具体类型,刚好匹配F的要求,因此能正常编译。移除
'a后的情况:此时Tasks<F>的函数指针类型会被编译器推断为需要支持任意生命周期组合(即for<'r, 's> fn(&'r str, &'s Component) -> F),意思是这个函数指针要能接受任意生命周期的&str和&Component,并且始终返回同一个F类型的Future。但download函数的返回值impl Future是和它的输入生命周期强绑定的——不同的输入生命周期会生成不同的Future类型,无法做到对所有生命周期都返回同一个固定的F,这就导致了编译器报错的“类型通用性不匹配”问题。
内容的提问来源于stack exchange,提问作者lucian
相关产品推荐
相关产品推荐

