3

I was just reading about mut and how it differs from &mut, and when you want to use the two. So I was going through this article.

The article has this code snippet, where two mutable references are made to the same variable:

fn main() {
   let mut i:i32 = 1;
   let ref_i = &mut i;
   let another_ref_i = &mut i;
}

According to the article, this should fail, because two active mutable references are not allowed, so it should fail with this error:

error[E0499]: cannot borrow `i` as mutable more than once at a time
 --> src/main.rs:4:29
  |
3 |    let ref_i = &mut i;
  |                     - first mutable borrow occurs here
4 |    let another_ref_i = &mut i;
  |                             ^ second mutable borrow occurs here
5 | }
  | - first borrow ends here

But this does not happen for me. For me it compiles fine.

I then looked in the rust handbook, for a similar example, and found this:

fn main() {
    let mut x = 5;
    let y = &mut x;

    *y += 1;

    println!("{}", x);
}

Which should fail with the same error. But does'nt.

This confuses me I thought that a mutable reference would disallow the borrowed value to be used for the rest of the code.

Can someone help me with what it happening?

Grazosi
  • 603
  • 1
  • 10
  • See https://stackoverflow.com/questions/57055461/why-can-we-have-multiple-mutable-references-to-the-same-data-in-the-same-scope. – Dogbert Apr 28 '22 at 18:25
  • 1
    In principle, those code segments should fail. But Rust is pretty clever nowadays when it comes to dropping values that aren't used. Basically, when you do a second mutable borrow, if Rust can prove that the first one is never used again, it will just quietly drop the first one rather than complaining about it. – Silvio Mayolo Apr 28 '22 at 18:26
  • Rust inserts a `drop(y)` after the last use of `y`, which allows your code to work. This interpretation doesn't affect Rust's guarantees, and makes many valid patterns compile that previously failed. As others pointed out, look up non-lexical lifetimes for details. – user4815162342 Apr 28 '22 at 19:00
  • Nitpick: Rust doesn't "insert a `drop(y)`." That's unnecessary. (If it did, NLL wouldn't work without std.) The compiler is capable of realizing NLL itself, without calling std functions. – cdhowie Apr 28 '22 at 22:44
  • @cdhowie `drop` is part of `core` so it works without std… – Jmb Apr 29 '22 at 07:41
  • @Jmb Regardless, `drop()` is a mechanism for _us_ that explicitly destroys a value. The compiler is able to realize NLL without emitting additional function calls. – cdhowie Apr 29 '22 at 18:32
  • @cdhowie, if you really want to nitpick, the compiler doesn't emit any function calls for `drop(y)` either: `drop` gets inlined and since its body is empty it disappears. Regardless of what the compiler really does behind the scene, saying that it (behaves as if it) inserts `drop` is a great way to explain what happens without getting lost in irrelevant details. – Jmb Apr 30 '22 at 15:29

0 Answers0