Rust trait方法返回trait object时无法推断合适生命周期报错
问题描述
我尝试实现一个支持新增引用条目、操作不影响原有版本的不可变Dictionary trait,最小复现代码如下:
#[derive(Clone)] pub struct SetOfValues<'a> { value: Vec<&'a i32>, } pub trait TheSetAccessor<'b> { fn with_additional_values(&self, new_set: Vec<&'b i32>) -> Box<dyn TheSetAccessor<'b>>; fn get_from_set(&self, index: usize) -> &i32; } impl<'a, 'b : 'a> TheSetAccessor<'b> for SetOfValues<'a> { fn with_additional_values(&self, new_set: Vec<&'b i32>) -> Box<dyn TheSetAccessor<'b>> { Box::new(SetOfValues { value: new_set } ) } fn get_from_set(&self, index: usize) -> &i32 { self.value[index] } } fn usage() { let a = 0; let set = SetOfValues { value: vec![&a] }; // ... let b = 1; let extended_set = set.with_additional_values(vec![&a, &b]); // ... let got_b = extended_set.get_from_set(1); }
编译时触发如下错误信息:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> src/test.rs:13:18 | 13 | Box::new(SetOfValues { value: new_set } ) | ^^^^^^^^^^^ | note: first, the lifetime cannot outlive the lifetime `'b` as defined here... --> src/test.rs:11:10 | 11 | impl<'a, 'b : 'a> TheSetAccessor<'b> for SetOfValues<'a> { | ^^ note: ...so that the expression is assignable --> src/test.rs:13:39 | 13 | Box::new(SetOfValues { value: new_set } ) | ^^^^^^^ = note: expected `Vec<&i32>` found `Vec<&'b i32>` = note: but, the lifetime must be valid for the static lifetime... note: ...so that the types are compatible --> src/test.rs:13:9 | 13 | Box::new(SetOfValues { value: new_set } ) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected `Box<(dyn TheSetAccessor<'b> + 'static)>` found `Box<dyn TheSetAccessor<'b>>`
按照我的理解,新创建的SetOfValues实例应当持有传入vector的生命周期'b,但错误提示表明返回的dyn trait默认被要求满足'static生命周期约束,与'b存在冲突。需要明确正确的生命周期约束写法让代码正常编译。
错误原因
报错核心来自两个Rust生命周期规则的默认行为:
dyn Traittrait对象默认带'static生命周期约束:如果没有显式给trait对象标注生命周期,放在Box中返回时编译器会默认要求它满足'static,即不能持有任何非全局静态的引用,和代码中持有'b生命周期的栈引用冲突。- 生命周期约束多余且干扰推断:原代码中
'b: 'a的约束要求'b生命周期长于'a,但当前with_additional_values返回的是全新的SetOfValues实例,和原实例的'a生命周期没有直接关联,该约束反而让编译器无法匹配正确的生命周期。
修复方案
只需要两处修改即可让代码正常编译:
- 给trait方法返回的trait对象显式加上
+ 'b生命周期绑定,告诉编译器这个trait对象只需要和内部引用的'b生命周期匹配即可,不需要满足'static要求。 - 移除impl块中多余的
'b: 'a约束(如果后续要实现新旧值合并的逻辑,可以再加回该约束,利用引用的协变特性将短生命周期的引用统一转为长生命周期的'b引用)。
修复后的完整可运行代码:
#[derive(Clone)] pub struct SetOfValues<'a> { value: Vec<&'a i32>, } pub trait TheSetAccessor<'b> { // 显式标注trait对象的生命周期,匹配内部引用的'b fn with_additional_values(&self, new_set: Vec<&'b i32>) -> Box<dyn TheSetAccessor<'b> + 'b>; fn get_from_set(&self, index: usize) -> &i32; } impl<'a, 'b> TheSetAccessor<'b> for SetOfValues<'a> { fn with_additional_values(&self, new_set: Vec<&'b i32>) -> Box<dyn TheSetAccessor<'b> + 'b> { Box::new(SetOfValues { value: new_set }) } fn get_from_set(&self, index: usize) -> &i32 { self.value[index] } } fn usage() { let a = 0; let set = SetOfValues { value: vec![&a] }; let b = 1; let extended_set = set.with_additional_values(vec![&a, &b]); let got_b = extended_set.get_from_set(1); assert_eq!(*got_b, 1); }
如果后续要实现真正的不可变扩展(新集合同时包含原有值和新增值,原集合不受影响),可以把with_additional_values的实现改成合并两个vec的内容,加回'b: 'a约束即可,因为'b长于'a时&'a i32可以自动转换为&'b i32,示例实现:
impl<'a, 'b: 'a> TheSetAccessor<'b> for SetOfValues<'a> { fn with_additional_values(&self, new_set: Vec<&'b i32>) -> Box<dyn TheSetAccessor<'b> + 'b> { let mut merged = self.value.clone(); merged.extend(new_set); Box::new(SetOfValues { value: merged }) } fn get_from_set(&self, index: usize) -> &i32 { self.value[index] } }
内容的提问来源于stack exchange,提问作者Defake
相关产品推荐
相关产品推荐

