This code doesn't compile with rust == 1.35 but is validated by the borrow checker of later versions. What changes of the borrowing rules make that possible ?
fn main()
{
let mut x = 0;
let r_x = &mut x;
*r_x = 0;
let r_x_2 = &mut (*r_x);
*r_x_2 = 8;
*r_x = 7;
println!("{}", x);
}
The reason why intuitively the compiler accepts this code is that after the *r_x_2 = 8; line the variable r_x_2 is no longer considered alive, and thus r_x becomes usable again.
With the 1.35 version of the compiler you had to manually add scopes to hint this to the compiler:
fn main() {
let mut x = 0;
{
let r_x = &mut x;
*r_x = 0;
{
let r_x_2 = &mut (*r_x);
*r_x_2 = 8;
}
*r_x = 7;
}
println!("{}", x);
}
What puzzled me the most was the fact that if I replace &mut (*r_x) by &mut x it doesn't pass. So I guess the compiler consider we can borrow from a borrow, which I didn't take into account in my mental model.
Speaking of mental models... Here's a fun thread to look into in case your goal is (to read a shit-ton of large amount of replies and) to deepen, or improve, your “mental model” for borrowing.