It's not a second borrow, it's reborrow of the first one. Note that, if you swap two printlns, the code will not compile:
error[E0502]: cannot borrow `r1` as immutable because it is also borrowed as mutable
--> src/main.rs:6:16
|
4 | let r2 = &mut *r1;
| -------- mutable borrow occurs here
5 |
6 | println!("{r1}");
| ^^ immutable borrow occurs here
7 | println!("{r2}");
| -- mutable borrow later used here
|
That is, when you do r2 = &mut *r1, you temporarily render r1 unusable, as long as its reborrow is being used.
I understand if I uncomment the first let that I will get an error but not that the second let succeeds. Rust analyzers tells me that r2 is of type &mut String which appears to me that we now have two mutable borrows coexisting which shouldn't be possible from what I learned so far. After all the commented out let fails (as expected) because it tries to get another mutable borrow but the 2nd let succeeds in doing so.
You say this is a reborrow. I quickly searched the docs for the term reborrow but nothing showed up. Is there something I can read up on that explains this behavior?
Point is, they're not coexisting - the first is temporarily non-existing while you're using the second, since the second is created from the first, not directly from the referenced object.
It's not really possible to write a set of rules which would both reject all unsound programs and accept all sound programs.
That's why set of rules in the Reference is conservative. All the programs which follow these rules are accepted, but not all programs which violate them are rejected because rust developers are regularly adjusting rules and try to accomodate more design patters. Sometimes without adding these exceptions to the documentation.
That's why you may suddenly find out that something which you expected to fail works, for some reason: unless you program is actually unsound (e.g. it creates two references which are actually alive at the same time) most likely cause is that you have hit some of these relaxations.
Of course if you can demonstrate that program is actually unsound… it's different story.
I read the posted links here and I understand now roughly what a reborrow is, what purpose it serves and how it works (stacked borrow model).
That really needs to be mentioned in the book and the docs. Once you set out to test what you just learned about ownership and borrows you'll run into it and confusion sets in.