4

我有一个带有函数的结构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
4

1 回答 1

7

问题在这里:

impl<'a> B<'a> {
    fn next(&self) -> B {
        let mut new = self.clone();
        new.0 = new.0 + 1;
        new
    }
}

您没有为B的返回类型指定生命周期next。由于 Rust 的生命周期省略规则,编译器会推断出您的意图:

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我们知道不存在这样的关系——生命周期注释并不反映你实际所做的事情的约束。

那么这里的生命周期是什么?

  1. 引用的生命周期B是不相关的——每一个都可以独立存在。因此,为了给调用者最大的灵活性, 的生命周期B应该不同于对selfin的引用的生命周期next

  2. 然而每一个B由. 所以你给每个人的生命周期参数必须是相同的。next() u32selfB

使用显式命名的生命周期,这是结合这两件事的结果:

impl<'a> B<'a> {
    fn next<'c>(&'c self) -> B<'a> {
        let mut new = self.clone();
        new.0 = new.0 + 1;
        new
    }
}

请注意——即使对这里的引用有生命周期——类型是,其中是内部的生命周期。与返回值相同。self'cselfB<'a>'a&u32

但实际上,'c可以省略。所以它真的和这个一样:

impl<'a> B<'a> {
    fn next(&self) -> B<'a> {
        let mut new = self.clone();
        new.0 = new.0 + 1;
        new
    }
}
于 2018-06-02T11:29:29.430 回答