The following natural language translation seems to clear things up for me...
let x = value;
x {binds immutably} to {immutable value}
let mut x = value;
x {binds mutably} to {possibly mutable value}
let x = &value;
x {binds immutably} to {a reference to} {immutable value}
let x = &mut value;
x {binds immutably} to {a reference to} {mutable value}
let mut x = &value;
x {binds mutably} to {a reference to} {immutable value}
let mut x = &mut value;
x {binds mutably} to {a reference to} {mutable value}
where
{binds mutably}
means the binding can be reassigned
{mutable value}
means the value's contents can change
- To be able to mutate a value you need both a mutable binding and a mutable value
Note:
Reference mutability vs target mutability
A reference variable such as x
, as in let x = &mut y
, is a separate variable from the target variable y
it is pointing to. In particular, x
has its own location on the stack and mutability permissions. As such, if x
is immutable, as it is here, then it cannot be reassigned to point to some other variable. That restriction is separate from the ability to mutate the target through it, as in *x = some_value
; the target is a distinct variable with its own mutability permissions. However, if w
is mutable, as in let mut w = &mut p
, then it can indeed be reassigned to point to some other similarly typed variable: w = &mut z
.