Rust - Why does dereferencing and borrowing break borrowing rules?

Viewed 78

As per my understanding, there can be multiple immutable references at a time but if there is a mutable reference it can be the only usable reference.

Why does the following code work?:

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());
}

Edit: Another part of my question which I guess isn't obvious is: why am I not allowed to create f3 (like I am doing in the commented line) when it is exactly the same thing as f2 and created similarly by refrencing y.

1 Answers

Because the compiler is smart enough to know if the data actually is used as mutable before it is used as immutable. If you change the code at all to use the mutable reference first, it fails.

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());
}

Here's a link to a live example. The error, as you'd expect, mentions you cannot have an immutable reference if a mutable one exists.

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

In short, you can only have one borrow if you have a mutable reference, but the compiler is intelligent enough to know when the value cannot change: in your example, f cannot change when it is used before f2 is used, so it knows it doesn't change.

Related