我有一个带有函数next()
的结构(类似于迭代器但不是迭代器)。此方法返回修改后的下一个状态(保留原始状态)。所以:fn next(&A) -> A
。
我从一个简单的结构开始,我不需要生命周期(示例中的结构A),我扩展它以添加对新结构(结构B)的引用。
问题是我现在需要指定结构的生命周期,由于某种原因我的方法next()
拒绝再使用了。
我怀疑每次迭代的新结构的生命周期都限于创建它的范围,我不能将它移到这个范围之外。
是否可以保留next()
方法的行为?
#[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
答案 0 :(得分:7)
问题在于:
impl<'a> B<'a> {
fn next(&self) -> B {
let mut new = self.clone();
new.0 = new.0 + 1;
new
}
}
您没有为B
指定生命周期,返回类型为next
。由于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
}
}
这意味着返回值可能不会超过self
。或者换句话说,self
必须比返回的B
更长寿。鉴于函数的主体,这是完全不必要的要求,因为这些引用是相互独立的。它在这里引起了一个问题:
for _ in 0..5 {
b = b.next();
}
您正在覆盖借用检查者认为仍被next()
调用借来的值。在next
内部我们知道没有这样的关系 - 生命期注释并不反映你实际做的事情的限制。
那么这里的生命界限是什么?
对B
的引用的生命周期是不相关的 - 每个引用都可以不存在另一个。因此,为了给调用者提供最大的灵活性,B
的生命周期应与self
中对next
的引用的生命周期不同。
但是,使用B
创建的每个next()
都包含对{em>与u32
相同的 self
的引用。因此,您为每个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
1}}是&u32
内部的生命周期。与返回值相同。
但实际上,'c
可以省略。所以它实际上就是这样:
impl<'a> B<'a> {
fn next(&self) -> B<'a> {
let mut new = self.clone();
new.0 = new.0 + 1;
new
}
}