How to change what a mutable reference points at
Short answer: To put a new value where a &mut reference points, write through it:
*r = other;. The mut does not go on the binding — let r = &mut total; is already writable,
because the mutability lives in the reference’s type, &mut, not in the variable that holds it.
Adding mut to the binding means something else entirely: that the reference itself may be
re-pointed at a different place.
Write through it, not at it
Section titled “Write through it, not at it”Start from a fresh project — cargo new ref-point, then replace src/main.rs with the whole of
each file below.
fn main() { let mut total = 3; let r = &mut total; *r = 10; println!("total = {total}");}total = 10The assignment *r = 10 does not touch r at all. r still holds the same address; what changed
is the memory it aims at. And note the bindings: total is mut, r is not, yet the write
compiles without a murmur.
That is what mut on a binding actually controls: whether the name can be assigned again.
*r = 10 never assigns to r — it dereferences and assigns through it, so mut r would be beside
the point.
The mutability has to come from somewhere
Section titled “The mutability has to come from somewhere”For the borrow to be a &mut at all, the owner must allow mutation:
fn main() { let total = 3; let r = &mut total; println!("{r}");}error[E0596]: cannot borrow `total` as mutable, as it is not declared as mutable --> src/main.rs:3:13 |3 | let r = &mut total; | ^^^^^^^^^^ cannot borrow as mutable |help: consider changing this to be mutable |2 | let mut total = 3; | +++
For more information about this error, try `rustc --explain E0596`.The complaint is about total, not r: a value that has promised never to change cannot hand out
a write handle. So the mutability is anchored in two places — the owner’s mut makes the value
writable, the &mut type makes this particular borrow a writer — and the binding that holds the
reference stays out of it.
Re-pointing is the other operation
Section titled “Re-pointing is the other operation”Making the reference aim somewhere else is an assignment to r, and that is the case where the
binding’s mut matters:
fn main() { let mut a = 1; let mut b = 2; let r = &mut a; r = &mut b; println!("{a} {b}");}error[E0384]: cannot assign twice to immutable variable `r` --> src/main.rs:5:5 |4 | let r = &mut a; | - first assignment to `r`5 | r = &mut b; | ^^^^^^^^^^ cannot assign twice to immutable variable |help: consider making this binding mutable |4 | let mut r = &mut a; | +++
For more information about this error, try `rustc --explain E0384`.Declare the binding mut and both operations work side by side:
fn main() { let mut a = 1; let mut b = 2; let mut r = &mut a; *r = 10; r = &mut b; *r += 100; println!("a = {a}, b = {b}");}a = 10, b = 102Up to r = &mut b;, the reference aims at a, so *r = 10 sets a. After the re-pointing it aims
at b, so *r += 100 sets b. Two different jobs — writing through the pointer, and moving the
pointer — and only the second one needs mut on the binding.
The everyday use: a function that replaces a value
Section titled “The everyday use: a function that replaces a value”Most *r = ... in real code sits inside functions that take a &mut parameter:
fn main() { let mut top = String::from("b"); replace(&mut top, String::from("winner")); println!("top = {top}");}
fn replace(slot: &mut String, value: String) { *slot = value;}top = winner*slot = value behaves exactly like assigning to the variable itself: the old "b" is dropped in
place and the new value takes over the same memory. The caller keeps owning the String — the
function only ever held a write handle to the slot, and when it returns, the handle is gone.
Related
Section titled “Related”- What is the difference between & and &mut?
— what the
mutin the type promises - What is reborrowing? — why a
&mutkeeps working as it is passed along - How to end a borrow early — when a borrow lasts longer than you wanted
- Borrowing — the rest of this chapter