Rust - 解引用和借用为什么会破坏借用规则?

3

据我所知,在同一时间可以有多个不可变引用,但如果存在一个可变引用,则它将是唯一的可用引用。

为什么以下代码有效?

fn main() {
    let mut y = String::from("bar");

    let f: &mut String = &mut y;
    let f2: &String = &(*f);

    // not allowed since mutable reference already exists
    // let f3: &String = &y; 

    println!("{}, ", f.as_str());
    println!("{}", f2.as_str());
}

编辑:我的另一个问题是,我猜想并不明显:为什么我不能创建f3(如我在注释行中所做的那样),它与f2完全相同且通过引用y类似地创建。

编辑:我猜想并不明显的另一个问题是:当我像在注释行中所做的那样创建f3时,为什么不被允许,它与f2完全相同,并通过引用y类似地创建。

不是与此问题完全相关,但“如果存在可变引用,则它可以是唯一的引用”并不完全正确。我认为你想要表达的是,“如果存在可变引用,则它可以是唯一可用的引用。” - cdhowie
1个回答

1

编译器非常聪明,能够在数据被用作不可变之前判断其是否实际用作可变。如果您更改代码以首先使用可变引用,则会失败。

fn main() {
    let mut y = String::from("bar");

    let f: &mut String = &mut y;
    let f2: &String = &(*f);
    f.clear();

    // not allowed since mutable reference already exists
    // let f3: &String = &y; 

    println!("{}, ", f.as_str());
    println!("{}", f2.as_str());
}

这是一个链接到实时示例的链接。错误提示中提到,如果存在可变引用,则不能有不可变引用。请点击此处查看示例。
error[E0502]: cannot borrow `*f` as mutable because it is also borrowed as immutable
  --> src/main.rs:6:5
   |
5  |     let f2: &String = &(*f);
   |                       ----- immutable borrow occurs here
6  |     f.clear();
   |     ^^^^^^^^^ mutable borrow occurs here
...
12 |     println!("{}", f2.as_str());
   |                    ----------- immutable borrow later used here

For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` due to previous error

简而言之,如果您拥有一个可变引用,则只能有一个借用,但编译器足够智能,可以知道值何时不会改变:在您的示例中,在使用f2之前使用f时,f不能更改,因此它知道它不会更改。

我认为编译器不必重新排列任何内容,我认为这能够工作的原因是因为编译器发现 f.as_str() 只需要一个不可变引用。因此,即使 f 是一个可变引用,在 let f 行之后没有任何东西需要对 y 进行可变访问。 - cdhowie
@cdhowie 我误读了原始借用的顺序,但是没错。基本上,编译器知道不需要可变借用。 - Alex Huszagh
但是为什么它会阻止创建“f3”呢?这与“f2”是一样的东西。 - user3690467
@user3690467 很好的问题。我猜是因为顺序很重要?我猜它足够聪明来处理 f2,但对于 f3 来说不够聪明。它必须理解在 f3 中有一个额外的借用深度,而我猜它做不到。在 f3 中,你首先从 y 可变地借用,然后再次从 y 不可变地借用。在 f2 中,你首先从 y 可变地借用,然后从可变借用中不可变地借用。所以在 f2 中,你有一条线性链,而在 f3 中,你有一种分叉的情况。 - Finomnis

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