只有一个可变引用,为什么会出现第二个可变借用错误?

4

这段代码并没有太多意义,因为无论是否使用if let,它都会返回同样的结果,但它是我遇到的问题的一个简洁例子:

struct Data {
    value: Option<i32>,
}

impl Data {
    fn get(&mut self) -> Option<&mut i32> {
        if let Some(val) = &mut self.value {
            return Some(val);
        }

        return self.value.as_mut();
    }
}

这段代码产生了错误:

error[E0499]: cannot borrow `self.value` as mutable more than once at a time
  --> src/lib.rs:11:16
   |
6  |     fn get(&mut self) -> Option<&mut i32> {
   |            - let's call the lifetime of this reference `'1`
7  |         if let Some(val) = &mut self.value {
   |                            --------------- first mutable borrow occurs here
8  |             return Some(val);
   |                    --------- returning this value requires that `self.value` is borrowed for `'1`
...
11 |         return self.value.as_mut();
   |                ^^^^^^^^^^ second mutable borrow occurs here

我不明白为什么这是第二个可变借用,因为第一个在第二个发生之前就已经超出其作用域了。

if let之后,变量val不在作用域中,那么它怎么会是第二个借用呢?第一个借用应该已经被释放了。

为了确保,我甚至将if let包裹在另一个块中:

{
    if let Some(val) = &mut self.value {
        return Some(val);
    }
}

return self.value.as_mut();

这导致了相同的错误。这里发生了什么?

顺便说一下,在 Rust 中,在块的末尾使用显式的 return 不是惯用语。 - Shepmaster
1个回答

9
'a的生命周期包括整个函数体,因为返回值需要借用self。因此,第一个借用的作用域延伸到if表达式并延伸到整个函数体。

非词法生命周期旨在通过将第一个借用的范围缩小到仅包括if表达式来解决这个问题。您可以通过将借用的值移动到本地变量(playground)中查看其效果:

fn get(&mut self) -> Option<&mut i32> {
    let value = &mut self.value;
    if let Some(val) = value {
        return Some(val);
    }
    return value.as_mut();
}

然而,支持有条件地返回值的功能已被删除,因为它需要太多的编译时间。该功能仍在开发中,可以通过-Zpolonius标志启用:
RUSTFLAGS="-Zpolonius" cargo +nightly build 使用此方法,原始代码可以成功编译。

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