Rust返回Box<dyn trait>时出现生命周期冲突的原因是什么?
错误原因
这个报错是Rust的trait对象默认生命周期规则和你代码里的实际生命周期约束冲突导致的,具体原因如下:
- Rust中如果没有显式指定生命周期,
dyn Trait形式的trait对象默认自带'static生命周期约束。你写的返回值Box<dyn E>默认要求里面的内容必须满足'static生命周期,也就是要能在整个程序运行期间有效。 - 你的
Bar<'a>结构体持有Foo内部T的引用,这个引用的生命周期和Foo实例本身的生命周期完全绑定,远达不到'static的要求,自然没办法塞进默认要求'static的Box<dyn E>里,所以编译器会抛出生命周期不匹配的错误。
为什么编译器要求'static约束
这是Rust的语法默认规则:当trait对象没有显式标注生命周期时,会按照以下优先级推导生命周期约束:
- 如果trait本身定义了生命周期约束,优先使用trait的生命周期
- 如果trait对象是
&'a dyn Trait或者&'a mut dyn Trait,默认生命周期是'a - 如果是智能指针包裹的trait对象比如
Box<dyn Trait>,默认生命周期就是'static
你的代码正好命中了第三种情况,所以编译器默认要求返回的trait对象满足'static约束。
解决方案
按照编译器提示修改foo方法的返回值即可:
fn foo(&mut self) -> Box<dyn E + '_> { let t = self.peek(); Box::new(Bar::new(t).unwrap()) }
这里的'_是匿名生命周期标注,意思是返回的trait对象的生命周期和输入参数&mut self的生命周期绑定,相当于显式告诉编译器这个trait对象不需要和程序生命周期一样长,只要和当前Foo实例生命周期一致即可,和Bar的生命周期约束匹配,自然就能编译通过。
如果不想让返回的trait对象和Foo实例绑定生命周期,也可以修改Bar的定义,让它持有T的所有权而非引用,这就要求你要么实现T的Clone trait,要么把对应位置的T从Foo的Vec中转移所有权出来,这种情况也不需要修改返回值的生命周期标注。
内容的提问来源于stack exchange,提问作者Ach113
相关产品推荐
相关产品推荐

