我有一个带有函数next()的结构(类似于迭代器但不是迭代器).此方法返回修改后的下一个状态(保留原始状态).所以:fn next( A) – 一个. 我从一个简单的结构开始,我不需要生命周期(示例中
我从一个简单的结构开始,我不需要生命周期(示例中的结构A),我扩展它以添加对新结构(结构B)的引用.
问题是我现在需要指定我的struct的生命周期,由于某种原因我的方法next()拒绝再工作了.
我怀疑每次迭代的新结构的生命周期都限于创建它的范围,我不能将它移到这个范围之外.
是否可以保留next()方法的行为?
Try it here
#[derive(Clone)] struct A(u32); #[derive(Clone)] struct B<'a>(u32, &'a u32); impl A { fn next(&self) -> A { let mut new = self.clone(); new.0 = new.0 + 1; new } } impl<'a> B<'a> { fn next(&self) -> B { let mut new = self.clone(); new.0 = new.0 + 1; new } } fn main() { let mut a = A(0); for _ in 0..5 { a = a.next(); } let x = 0; let mut b = B(0, &x); for _ in 0..5 { b = b.next(); } }
错误是:
error[E0506]: cannot assign to `b` because it is borrowed --> src/main.rs:31:9 | 31 | b = b.next(); | ^^^^-^^^^^^^ | | | | | borrow of `b` occurs here | assignment to borrowed `b` occurs here问题出在这里:
impl<'a> B<'a> { fn next(&self) -> B { let mut new = self.clone(); new.0 = new.0 + 1; new } }
您没有为B指定生命周期,即下一步的返回类型.由于Rust的lifetime elision rules,编译器推断你打算这样做:
impl<'a> B<'a> { fn next<'c>(&'c self) -> B<'c> { let mut new = self.clone(); new.0 = new.0 + 1; new } }
这意味着返回值可能不会超过自我.或者换句话说,自我必须比返回的B长寿.鉴于函数的主体,这是一个完全不必要的要求,因为这些引用是相互独立的.这会导致一个问题:
for _ in 0..5 { b = b.next(); }
您正在覆盖借用检查器认为仍然通过调用next()借用的值.接下来我们知道没有这样的关系 – 终身注释并不反映你实际做的事情的限制.
那么这里的生命界限是什么?
>对B的引用的生命期是无关的 – 每个都可以不存在另一个.因此,为了给调用者提供最大的灵活性,B的生命周期应该与下一个自我引用的生命周期不同.
>但是,使用next()创建的每个B都包含对self所持有的相同u32的引用.因此,您为每个B提供的生命周期参数必须相同.
使用明确命名的生命周期,这是结合这两件事的结果:
impl<'a> B<'a> { fn next<'c>(&'c self) -> B<'a> { let mut new = self.clone(); new.0 = new.0 + 1; new } }
注意 – 即使这里对self的引用具有生命周期’c – self的类型是B<'a>,其中’a是& u32里面的生命周期.与返回值一样.
但实际上,’c可以省略.所以它真的和这个一样:
impl<'a> B<'a> { fn next(&self) -> B<'a> { let mut new = self.clone(); new.0 = new.0 + 1; new } }