在循环中的可变借用

8

我有以下代码:

struct Baz {
    x: usize,
    y: usize,
}

struct Bar {
    baz: Baz,
}

impl Bar {
    fn get_baz_mut(&mut self) -> &mut Baz {
        &mut self.baz
    }
}

struct Foo {
    bar: Bar,
}

impl Foo {
    fn foo(&mut self) -> Option<&mut Baz> {
        for i in 0..4 {
            let baz = self.bar.get_baz_mut();
            if baz.x == 0 {
                return Some(baz);
            }
        }
        None
    }
}

Rust Playground

编译失败,错误信息如下:

error[E0499]: cannot borrow `self.bar` as mutable more than once at a time
  --> src/main.rs:23:23
   |
23 |             let baz = self.bar.get_baz_mut();
   |                       ^^^^^^^^ mutable borrow starts here in previous iteration of loop
...
29 |     }
   |     - mutable borrow ends here

然而,如果我从Foo::foo返回Some(baz.x)(并将返回类型更改为Option<usize>),则代码编译。这使我相信问题不在于循环,尽管编译器似乎表明如此。更具体地说,我认为局部可变引用baz将在下一次循环迭代时超出范围,导致这不是问题。上述代码的生命周期问题是什么?
以下问题类似: 然而,它们处理明确声明的生命周期(特别是这些明确的生命周期是答案的一部分)。我的代码省略了这些生命周期,因此删除它们并不是一个解决方案。

我很惊讶在SO上没有找到这个问题的副本,但我通常不擅长搜索问题。也许是因为你的例子不太习惯用语,或者太简单了,无法表达实际问题。 - Stargateur
1个回答

5
它无法工作,因为返回已借用的值会将借用延长到函数的末尾。
有关一些有用的详细信息,请参见此处
这适用于非词法生命周期1.27夜间版本。
#![feature(nll)]

struct Baz {
    x: usize,
    y: usize,
}

// ...

非词法生命周期RFC解释了生命周期的实际工作方式:

然而,当引用跨越多个语句时会出现问题。在这种情况下,编译器要求生命周期为最内层表达式(通常是一个块),该块包含两个语句,并且通常比实际上需要或期望的要大得多

rustc nightly 1.28

如@pnkfelix所指出的那样, 从夜间版1.28开始,非词法生命周期的实现不再编译上述代码。

然而,有一个长期计划重新启用更强大的NLL分析


1
看起来当前版本的NLL不接受给定的确切代码;请参见此处的讨论 rust-lang/rust#43234 - pnkfelix

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接