调试Rust生命周期错误:如何正确指定生命周期参数?
Rust生命周期参数调试问题
我正在调试以下Rust代码,但无法正确指定生命周期参数:
use std::marker::PhantomData; #[derive(Clone, Debug, PartialEq)] pub enum FooBox<'a, T> { Ref(&'a Foo<T>), Own(Foo<T>), } #[derive(Clone, Debug, PartialEq)] pub struct Foo<T> { data: T, } impl<T> Foo<T> { /// Construct a new Foo pub fn new(data: T) -> Self { Self { data } } } pub trait Bar<C, P> where C: Clone, P: Clone, { fn iter<'a>(&'a self) -> impl Iterator<Item = (&'a C, FooBox<P>)> where C: 'a, P: 'a; } pub struct MyBar<'a, C, F0, F1, P0, P1> where C: Clone, F0: Bar<C, P0>, F1: Bar<C, P1>, P0: Clone, P1: Clone, { bar0: &'a F0, bar1: &'a F1, // Used for type checking at compile time c: PhantomData<C>, p0: PhantomData<P0>, p1: PhantomData<P1>, } impl<'a, C, F0, F1, P0, P1> MyBar<'a, C, F0, F1, P0, P1> where C: Clone, F0: Bar<C, P0>, F1: Bar<C, P1>, P0: Clone, P1: Clone, { /// Construct a new MyBar pub fn new(bar0: &'a F0, bar1: &'a F1) -> Self { Self { bar0, bar1, c: PhantomData, p0: PhantomData, p1: PhantomData, } } } impl<'a, C, F0, F1, P0, P1> Bar<C, (FooBox<'a, P0>, FooBox<'a, P1>)> for MyBar<'a, C, F0, F1, P0, P1> where C: Clone + PartialOrd, F0: Bar<C, P0>, F1: Bar<C, P1>, P0: Clone + PartialEq, P1: Clone + PartialEq, { fn iter<'b>(&'b self) -> impl Iterator<Item = (&C, FooBox<(FooBox<'a, P0>, FooBox<'a, P1>)>)> where C: 'b, P0: 'b, P1: 'b, { MyBarIter::new(self.bar0.iter(), self.bar1.iter()) } } /// Iterator for an MyBar pub struct MyBarIter<'a, C, I0, I1, P0, P1> where C: Clone + PartialOrd + 'a, I0: Iterator<Item = (&'a C, FooBox<'a, P0>)>, I1: Iterator<Item = (&'a C, FooBox<'a, P1>)>, P0: Clone + PartialEq + 'a, P1: Clone + PartialEq + 'a, { iter0: I0, iter1: I1, } impl<'a, C, I0, I1, P0, P1> MyBarIter<'a, C, I0, I1, P0, P1> where C: Clone + PartialOrd, I0: Iterator<Item = (&'a C, FooBox<'a, P0>)>, I1: Iterator<Item = (&'a C, FooBox<'a, P1>)>, P0: Clone + PartialEq, P1: Clone + PartialEq, { /// Construct a new iterator from the given MyBar pub fn new(iter0: I0, iter1: I1) -> Self { Self { iter0, iter1 } } } impl<'a, C, I0, I1, P0, P1> Iterator for MyBarIter<'a, C, I0, I1, P0, P1> where C: Clone + PartialOrd, I0: Iterator<Item = (&'a C, FooBox<'a, P0>)>, I1: Iterator<Item = (&'a C, FooBox<'a, P1>)>, P0: Clone + PartialEq, P1: Clone + PartialEq, { type Item = (&'a C, FooBox<'a, (FooBox<'a, P0>, FooBox<'a, P1>)>); fn next(&mut self) -> Option<Self::Item> { let next0 = self.iter0.next(); let next1 = self.iter1.next(); if let (Some((c0, p0)), Some((_, p1))) = (next0, next1) { return Some((c0, FooBox::Own(Foo::new((p0, p1))))); } return None; } }
编译时出现如下错误信息:
error: lifetime may not live long enough --> src/lib.rs:84:9 | 69 | impl<'a, C, F0, F1, P0, P1> Bar<C, (FooBox<'a, P0>, FooBox<'a, P1>)> | -- lifetime `'a` defined here ... 78 | fn iter<'b>(&'b self) -> impl Iterator<Item = (&C, FooBox<(FooBox<'a, P0>, FooBox<'a, P1>)>)> | -- lifetime `'b` defined here ... 84 | MyBarIter::new(self.bar0.iter(), self.bar1.iter()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a`
据我分析,self.bar0.iter()和self.bar1.iter()返回的迭代器所引用的数据,生命周期至少与拥有'a生命周期的self.bar0和self.bar1一致,但编译器无法识别这一点。请问如何正确指定生命周期参数以通过编译?
修复方案
1. 给iter方法添加生命周期约束
在MyBar的Bar trait实现中,给iter方法的'b生命周期添加'b: 'a约束,确保self的借用周期覆盖MyBar持有的引用周期:
impl<'a, C, F0, F1, P0, P1> Bar<C, (FooBox<'a, P0>, FooBox<'a, P1>)> for MyBar<'a, C, F0, F1, P0, P1> where C: Clone + PartialOrd, F0: Bar<C, P0>, F1: Bar<C, P1>, P0: Clone + PartialEq, P1: Clone + PartialEq, { fn iter<'b>(&'b self) -> impl Iterator<Item = (&'b C, FooBox<'b, (FooBox<'a, P0>, FooBox<'a, P1>)>)> where C: 'b, P0: 'b, P1: 'b, 'b: 'a, // 添加该约束 { MyBarIter::new(self.bar0.iter(), self.bar1.iter()) } }
2. 调整MyBarIter的生命周期参数
将MyBarIter的固定生命周期'a改为与输入迭代器匹配的'b,因为输入迭代器来自&'b self的借用,生命周期为'b:
/// Iterator for an MyBar pub struct MyBarIter<'b, C, I0, I1, P0, P1> where C: Clone + PartialOrd + 'b, I0: Iterator<Item = (&'b C, FooBox<'b, P0>)>, I1: Iterator<Item = (&'b C, FooBox<'b, P1>)>, P0: Clone + PartialEq + 'b, P1: Clone + PartialEq + 'b, { iter0: I0, iter1: I1, } impl<'b, C, I0, I1, P0, P1> MyBarIter<'b, C, I0, I1, P0, P1> where C: Clone + PartialOrd, I0: Iterator<Item = (&'b C, FooBox<'b, P0>)>, I1: Iterator<Item = (&'b C, FooBox<'b, P1>)>, P0: Clone + PartialEq, P1: Clone + PartialEq, { /// Construct a new iterator from the given MyBar pub fn new(iter0: I0, iter1: I1) -> Self { Self { iter0, iter1 } } } impl<'b, C, I0, I1, P0, P1> Iterator for MyBarIter<'b, C, I0, I1, P0, P1> where C: Clone + PartialOrd, I0: Iterator<Item = (&'b C, FooBox<'b, P0>)>, I1: Iterator<Item = (&'b C, FooBox<'b, P1>)>, P0: Clone + PartialEq, P1: Clone + PartialEq, { type Item = (&'b C, FooBox<'b, (FooBox<'a, P0>, FooBox<'a, P1>)>); fn next(&mut self) -> Option<Self::Item> { let next0 = self.iter0.next(); let next1 = self.iter1.next(); if let (Some((c0, p0)), Some((_, p1))) = (next0, next1) { return Some((c0, FooBox::Own(Foo::new((p0, p1))))); } None } }
核心原因说明
- 添加
'b: 'a约束后,编译器明确self的借用周期'b不短于MyBar中引用的'a周期,因此从bar0/bar1获取的迭代器数据可以安全满足'a的生命周期要求。 - 调整
MyBarIter的生命周期为'b,是因为输入迭代器的生命周期绑定到&'b self,而非MyBar的'a,这样迭代器的实现就能匹配输入的生命周期,消除不匹配错误。
内容的提问来源于stack exchange,提问作者student1868
相关产品推荐
相关产品推荐

