Rust调用dyn trait方法报错要求借用为'static的解决方法
问题复现
以下代码会触发生命周期报错:
pub struct IterOverVecVec<'a> { m: &'a dyn IterTrait, } impl<'a> Iterator for IterOverVecVec<'a> { type Item = u16; fn next(&mut self) -> Option<Self::Item> { Some(1) } } impl<'a> IterOverVecVec<'a> { fn new(m: &'a dyn IterTrait) -> Self { Self { m } } } pub trait IterTrait {} impl<'b> dyn IterTrait { pub fn get_iter<'a>(&'a self) -> IterOverVecVec<'a> { IterOverVecVec::new(self) } } pub struct HasAVec<'a> { m: &'a Vec<Vec<u16>>, } impl<'a> IterTrait for HasAVec<'a> {} impl<'a> HasAVec<'a> { pub fn new(m: &'a Vec<Vec<u16>>) -> Self { Self { m } } } #[test] fn fails() { let vecvec: Vec<Vec<u16>> = vec![vec![1, 2, 3], vec![4, 5, 6]]; let struct_with_vecs = HasAVec::new(&vecvec); let ni = <dyn IterTrait>::get_iter(&struct_with_vecs); }
对应的编译报错:
error[E0597]: `vecvec` does not live long enough --> src/lib.rs:41:41 | 41 | let struct_with_vecs = HasAVec::new(&vecvec); | ^^^^^^^ borrowed value does not live long enough 42 | let ni = <dyn IterTrait>::get_iter(&struct_with_vecs); | ----------------- cast requires that `vecvec` is borrowed for `'static` 43 | } | - `vecvec` dropped here while still borrowed
根因
Rust中未显式标注生命周期的trait对象类型dyn Trait,默认会携带'static生命周期约束,等价于dyn Trait + 'static。
代码中为dyn IterTrait写固有方法实现时,没有声明非'static的生命周期边界,编译器就默认这个trait对象必须满足'static要求。当把&struct_with_vecs转为&dyn IterTrait传参时,编译器要求struct_with_vecs内部持有的vecvec引用也必须存活到'static,和vecvec仅在测试函数作用域内存活的实际生命周期冲突,最终触发报错。
修复方法
两种方案都可以解决问题,按需选择即可:
方案1:给trait对象的固有实现显式添加生命周期参数
修改dyn IterTrait的固有实现块,显式声明支持任意生命周期,去掉默认的'static约束:
// 原代码为 impl<'b> dyn IterTrait { impl<'b> dyn IterTrait + 'b { pub fn get_iter<'a>(&'a self) -> IterOverVecVec<'a> where 'b: 'a, { IterOverVecVec::new(self) } }
修改后原测试代码不需要调整即可正常编译。
方案2:将方法直接定义在trait内(推荐)
把get_iter从trait对象的固有实现,挪到IterTrait的trait定义中作为默认方法,编译器会自动推导正确的生命周期,不需要手动标注复杂的生命周期边界,同时调用时也不需要写冗长的完全限定名:
pub trait IterTrait { fn get_iter(&self) -> IterOverVecVec<'_> { IterOverVecVec::new(self) } } // 删除原有的 impl<'b> dyn IterTrait { ... } 代码块
测试代码可以简化为直接调用方法:
#[test] fn works() { let vecvec: Vec<Vec<u16>> = vec![vec![1, 2, 3], vec![4, 5, 6]]; let struct_with_vecs = HasAVec::new(&vecvec); let ni = struct_with_vecs.get_iter(); }
内容的提问来源于stack exchange,提问作者TB_erryin
相关产品推荐
相关产品推荐

