let mut a = 1;
let b = &mut a;
let c = &mut *b; // changed to `&mut` for simplicity
leads to:
-
black arrows represent the relationship between an address and the memory it points to ("C pointers");
-
blue arrows represent the Stacked Borrows "authorization" / validity of such pointers:
-
b
is a valid pointer because it directly borrows the memory it points to (and it does so in an exclusive / unique manner, that's what themut
in&mut
means); -
Then
c
is valid in and on itself thanks to it (also exclusively) reborrowinga
through the borrowb
; it is as ifc
had borrowedb
's "license to accessa
": as long asc
is valid,b
cannot accessa
.
-
In other words, as soon as b
accesses a
, it means that c
must have (maybe implicitly) forfeited its "license to access a
", so as to have given it back to b
. At that point, c
becomes an invalidated / stale pointer: even though c
may still live in memory, and even though its value is a memory address that points to a
, Rust semantics forbid that such address be used to access a
.
And this is what happens when you do:
let d = *b;
-
That's why, for instance, doing afterwards
let e = *c;
leads to a compilation error. -
In your example however,
c
was not an exlusive (&mut
) borrow but a shared (&
) borrow; the situation is a bit more complex becauseb
andc
can still share access toa
, (e.g., both can read it). That's why this playground does compile. It's just that whilec
is valid,b
no longer has "exclusive access privileges" that would allow it to mutatea
, so ifb
ever does mutatea
, then the same reasoning as before applies and it means thatc
must have gotten invalidated beforehand.That's why the following code also fails to compile:
let mut a = 1; let b = &mut a; let c = &*b; *b = 42; // use `&mut`-ness of `b` let e = *c;
Now, regarding:
let mut a = 1;
let b = &mut a;
let c = &a;
we have:
- Indeed,
c
is directly borrowing froma
even though b was exclusively borrowinga
. This means thatb
must have implicitly forfeited its borrow and gotten invalidated.
This means that the following line let d = *b;
is actually using an invalidated borrow, hence the compilation error.
- But if it had been
let b = &a;
, then the borrow would have been shared andc
would have been allowed to also get shared access toa
without invalidating theb
borrow (Playground).