Trait对象生命周期与返回迭代器匹配触发生命周期错误咨询
问题分析
当前代码的核心问题在于Trait的生命周期参数'a被错误绑定到了函数的泛型生命周期,导致编译器认为foo需要存活到'a指定的生命周期,但foo是foo_bar_caller的局部变量,函数结束时就会被销毁,和'a的约束冲突:
- 定义的
Foo<'a>要求bar方法借用self的生命周期为'a,返回的迭代器也携带该生命周期; foo_bar_caller<'a>的参数Box<dyn Foo<'a>>意味着Trait对象的生命周期参数'a由调用者指定,而非函数内部的局部生命周期;- 调用
foo.bar()时,编译器判定*foo需要被借用整个'a周期,但foo在函数结束时就会销毁,因此触发“借用值存活时间不足”的错误。
方案一:用更高等级生命周期绑定(HRTB)调整Trait定义
将Trait的生命周期参数改为方法级别的HRTB,无需在Trait本身上声明生命周期参数,让方法对任意生命周期都有效:
trait Foo { fn bar<'a>(&'a self) -> Box<dyn Iterator<Item = usize> + 'a>; } struct FooImpl { values: Vec<usize> } impl Foo for FooImpl { fn bar<'a>(&'a self) -> Box<dyn Iterator<Item = usize> + 'a> { Box::new(self.values.iter().cloned()) } } fn foo_bar_caller(foo: Box<dyn Foo>) { let _iter = foo.bar(); } fn main() { let foo = FooImpl { values: vec![1, 2, 3, 4, 5] }; foo_bar_caller(Box::new(foo)); }
这种方式下,bar方法可接受任意生命周期的self借用,返回的迭代器生命周期与self的借用周期严格绑定,编译器能正确识别_iter和foo的生命周期都局限在函数内部,不会产生冲突。
方案二:调整函数参数的生命周期约束
若需保留Trait上的生命周期参数,可修改foo_bar_caller的参数,用匿名生命周期让'a约束为不超过foo的局部生命周期:
trait Foo<'a> { fn bar(&'a self) -> Box<dyn Iterator<Item = usize> + 'a>; } struct FooImpl { values: Vec<usize> } impl<'a> Foo<'a> for FooImpl { fn bar(&'a self) -> Box<dyn Iterator<Item = usize> + 'a> { Box::new(self.values.iter().cloned()) } } fn foo_bar_caller(foo: Box<dyn Foo<'_>>) { let _iter = foo.bar(); } fn main() { let foo = FooImpl { values: vec![1, 2, 3, 4, 5] }; foo_bar_caller(Box::new(foo)); }
这里的'_是匿名生命周期语法糖,告诉编译器Trait对象的生命周期参数就是foo本身的局部生命周期,调用bar时,借用周期与foo的存活周期完全匹配,函数结束时两者一起销毁,不会触发错误。
内容的提问来源于stack exchange,提问作者ysimonson
相关产品推荐
相关产品推荐

