Why would rust error on accessing mutable borrow while immutable borrow isn't accessed anywhere?

huangapple go评论77阅读模式
英文:

Why would rust error on accessing mutable borrow while immutable borrow isn't accessed anywhere?

问题

我无法理解为什么以下代码出错?
```rust
fn main() {
    let mut v = vec![];
    let z = &mut v;
    let y = &v;
    z.push(1);
    println!("{:?}", z); // 访问可变借用
}

在上述情况中,我没有在任何地方访问 y,而且 Rust 应该能够编译它而没有任何问题。我可以在下面的代码中看到类似的行为。

fn main() {
    let mut v = vec![];
    let y = &v;
    let z = &mut v;
    z.push(1);
    println!("{:?}", z); // 访问可变借用
}

在上述情况中,Rust 不会抱怨访问可变借用,因为没有在任何地方访问不可变借用。对于下面的情况,Rust 会抱怨,因为代码访问了不可变借用,这是完全可以理解的。

fn main() {
    let mut v = vec![];
    let y = &v;
    let z = &mut v;
    z.push(1);
    println!("{:?}", y); // 访问不可变借用
}

<details>
<summary>英文:</summary>

I&#39;m unable to understand why below code errors out ?
```rust
fn main() {
    let mut v = vec![];
    let z = &amp;mut v;
    let y = &amp;v;
    z.push(1);
    println!(&quot;{:?}&quot;,z); //accessing mutable borrow
}

In the above scenario, I'm not accessing y anywhere and rust should be able to compile it without any problems. I can see similar behavior happening in below code.

fn main() {
    let mut v = vec![];
    let y = &amp;v;
    let z = &amp;mut v;
    z.push(1);
    println!(&quot;{:?}&quot;,z); // accessing mutable borrow
}

In the above scenario, rust doesn't complain on accessing mutable borrow because immutable borrow isn't accessed anywhere. For below scenario rust complains as the code is accessing immutable borrow, which is completely understandable.

fn main() {
    let mut v = vec![];
    let y = &amp;v;
    let z = &amp;mut v;
    z.push(1);
    println!(&quot;{:?}&quot;,y); // accessing immutable borrow
}

答案1

得分: 4

即使你不访问 y,创建它就足以使任何现有的可变借用无效。

NLL(非词法生命周期) 改变的只是一个引用被认为存活直到其最后使用,而不是直到作用域的结束。但是引用总是被认为存活_一段时间_。

可以推测,你想要的行为没有被实现,因为它并不实用:一个从不被使用的引用几乎没有价值。

英文:

Even though you don't access y, creating it is enough to invalidate any existing mutable borrows.

What NLL (non-lexical lifetimes) changed is only that a reference is considered alive until its last usage, and not until the end of the scope. But a reference is always considered alive for some time.

Presumably, the behavior you want was not implemented because it's not useful: there is little value in reference that is never used.

答案2

得分: 2

问题不在于您是否正在访问 y,问题在于您在写 &amp;v 时实际上是在访问 v 本身。请注意,如果您从 z 创建 y,则您的代码将正常工作:

fn main() {
    let mut v = vec![];
    let z = &mut v;
    let y = &*z;
    z.push(1);
    println!("{:?}", z); // 访问可变引用
}

请注意,这在原始代码的错误消息中有所体现:

error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
 --&gt; src/main.rs:4:13
  |
3 |     let z = &mut v;
  |             ------ mutable borrow occurs here
4 |     let y = &v;
  |             ^^ immutable borrow occurs here
5 |     z.push(1);
  |     --------- mutable borrow later used here

错误标记 &amp;v 为问题所在,而不是 y

英文:

The problem isn't whether you're accessing y, the problem is that you're accessing v itself when you write &amp;v. Note that your code works if you create y from z:

fn main() {
    let mut v = vec![];
    let z = &amp;mut v;
    let y = &amp;*z;
    z.push(1);
    println!(&quot;{:?}&quot;,z); //accessing mutable borrow
}

Playground

Note that this is evidenced in the error message for your original code:

error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
 --&gt; src/main.rs:4:13
  |
3 |     let z = &amp;mut v;
  |             ------ mutable borrow occurs here
4 |     let y = &amp;v;
  |             ^^ immutable borrow occurs here
5 |     z.push(1);
  |     --------- mutable borrow later used here

The error marks &amp;v as problematic, not y.

答案3

得分: 1

2 条规则:

1- 不可变和可变引用不能同时存在于同一个变量上

2- 不可变引用的生命周期持续到最后一次使用

第一个代码失败,因为不可变和可变应该不应该同时存在(然而它们却同时存在,违反了Rust的借用规则)。变量 z 是可变的,它的作用域从第 3 行(let z = &amp;mut v;)开始,持续到第 6 行(println!(&quot;{:?}&quot;,z))。在这段时间内,不应该存在不可变引用。但是在这个作用域内确实存在不可变引用,它在第 4 行,即let y = &amp;v;

在第二个编译通过的代码中,不可变和可变不存在同时存在的情况。变量 y 是一个引用,其作用域从第 3 行开始并在该行结束(因为我们之后不再使用变量 y)。变量的作用域从第一次使用它的行开始,到最后一次使用它的行结束。

在第一个代码中,y 和 z 同时存在,而在第二个代码中,它们没有同时存在。

英文:

2 rules:

1- Immutable and mutable reference to the same variable cannot exist at the same time

2- The lifetime of an immutable reference lasts till its last usage

The first code fails because the immutable and mutable should not CO-EXIST (however they co-exist which is against rust borrowing rules). The variable z is mutable and its scope is from line 3 (let z = &amp;mut v;) till line 6 (println!(&quot;{:?}&quot;,z)
). During this duration, the immutable reference should not exist. However the immutable reference exists during this scope which is on line 4 which is let y = &amp;v;.

fn main() {
    let mut v = vec![];
    let z = &amp;mut v; // --------------------------------- its lifetime starts here 
    let y = &amp;v;   // y&#39;s lifetime start and ends here   |                              
    z.push(1); //                                       | z lifetime ends here                                                  
    println!(&quot;{:?}&quot;,z); 
  }
  // as you see y and z coexists

In the second code which compiles, is due to the fact that immutable and mutable does not co-exist. The variable y is a reference with a scope which starts and ends at the line 3 (since we are not using variable y afterwards). The scope of a variable starts from the line on which it is first used and ends on the line on which it is last used.

fn main() {
    let mut v = vec![];
    let y = &amp;v;  //      y&#39;s lifetime starts and ends here
    let z = &amp;mut v; //   z&#39;s lifetime starts here
    z.push(1);
    println!(&quot;{:?}&quot;,z); // accessing immutable borrow
}
// as you see y and z does not coexist

huangapple
  • 本文由 发表于 2023年7月18日 11:39:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76709394.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定