Why is this println!("{s}") treated as an immutable borrow?

This code is driving me crazy now.
The function is defined:

fn change(x: & mut String) {
    x.push_str(", changed");
}

The code with problem is:

    let mut s6=String::from("s6~~~");
    println!("before change: {s6}");
    change(&mut s6);
    println!("after change: {s6}");
    let s7=&mut s6;
    println!("{s7}");
    change(s7);
    println!("{s6}");//comment any line of these two will work
    println!("{s7}");//comment any line of these two will work

I can only keep one of the last two lines, otherwise I got error message as:

error[E0502]: cannot borrow `s6` as immutable because it is also borrowed as mutable
  --> src/main.rs:70:16
   |
67 |     let s7=&mut s6;
   |            ------- mutable borrow occurs here
...
70 |     println!("{s6}");
   |                ^^ immutable borrow occurs here
71 |     println!("{s7}");
   |                -- mutable borrow later used here
   |
   = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)

Why is printing treated as an ummutable borrow here in line 70?
I cannot move let s7=&mut s6; line up to just under s6 definition either.

I tried to simplify the problem by commenting many lines:

    let mut s6=String::from("s6~~~");
    // println!("before change: {s6}");
    // change(&mut s6);
    // println!("after change: {s6}");
    let s7=&mut s6;
    println!("{s7}");
    // change(s7);
    println!("{s6}");//comment anyline of these two will work again
    println!("{s7}");//comment anyline of these two will work again

Even this code doesn't compile, and the error message is the same. And if you comment any line of the last two, it will work again.
What is going on here, very Confusing! Thanks.

An immutable borrow (or re-borrow) of a mutable reference will keep alive the mutable borrow of the original value that this mutable reference constitutes.

See also: https://github.com/pretzelhammer/rust-blog/blob/master/posts/common-rust-lifetime-misconceptions.md#9-downgrading-mut-refs-to-shared-refs-is-safe (misconception number 9, “downgrading mut refs to shared refs is safe”)

3 Likes

&mut always represents exclusive access, and prevents all use of the referent that doesn’t go through the reference. Here, s7 holds exclusive access to s6 until its last use, which prevents the print of s6 from compiling.

Removing either of the two lines you mention means that you’re no longer trying to access s6 directly while s7 is still active, which then lets the code compile.

4 Likes

Thanks!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.