Exclusive Mutable References
In Rust, &mut T is more accurately described as an exclusive reference than merely a "mutable reference." While a shared reference &T permits any number of aliases to read the same data simultaneously, an active &mut T reference guarantees that it is the only path in the entire program currently allowed to access the target value.
Uniqueness Invariant of &mut T
For the duration of a &mut T borrow's lifetime (from the statement where &mut is taken until the last statement where that reference is used):
- No other
&mut Treference to the same value can be created (E0499). - No shared
&Treference to the same value can be created (E0502). - The original owner variable itself cannot be read, modified, or moved (
E0502/E0503/E0505).
Exclusive Access Window of `let r = &mut data;`:
let mut data = 10; <-- Owner `data` has full access
let r = &mut data; ──┬── Exclusive window starts: ONLY `r` can read/write!
*r += 5; │ (Reading `data` directly here is a compile error!)
println!("{r}"); ──┴── Last use of `r` -> Exclusive window ends!
println!("{data}"); <-- Owner `data` regains full access!
fn main() {
let mut balance = 500;
// Exclusive borrow starts here:
let exclusive: &mut i32 = &mut balance;
*exclusive += 250;
println!("Inside exclusive window: {exclusive}");
// Last use of `exclusive`! The exclusive window closes right here.
// Now the owner `balance` is accessible again:
balance -= 50;
println!("After exclusive window: {balance}");
}
Inside exclusive window: 750
After exclusive window: 700
Why &mut T Does Not Implement Copy
Unlike &T (which implements Copy so shared readers can be duplicated freely), &mut T intentionally does not implement Copy.
If you assign one mutable reference variable directly to another (let r2: &mut i32 = r1;) without reborrowing, ownership of the mutable reference moves from r1 into r2, rendering r1 unusable:
// ❌ does not compile
fn main() {
let mut x = 10;
let r1: &mut i32 = &mut x;
let r2: &mut i32 = r1; // Moves `r1` into `r2` because `&mut i32` is NOT `Copy`!
println!("{r1} and {r2}");
}
error[E0382]: borrow of moved value: `r1`
--> src/main.rs:6:15
|
3 | let r1: &mut i32 = &mut x;
| -- move occurs because `r1` has type `&mut i32`, which does not implement the `Copy` trait
4 | let r2: &mut i32 = r1;
| -- value moved here
5 |
6 | println!("{r1} and {r2}");
| ^^^^ value borrowed here after move
error: aborting due to 1 previous error
Disjoint Exclusive References via Splitting Methods
Sometimes an algorithm needs two simultaneous &mut references to different, non-overlapping parts of the same slice or array (for example, mutating the left half and right half of a buffer concurrently).
Because rustc cannot prove at compile time that two arbitrary runtime indices slice[i] and slice[j] are unequal (i != j), indexing &mut slice[i] twice fails with E0499. Instead, standard library methods such as .split_at_mut(mid) and .split_first_mut() verify non-overlap once and return two disjoint &mut references:
fn main() {
let mut scores = [10, 20, 30, 40, 50, 60];
// Safely obtain two simultaneous `&mut [i32]` slices to non-overlapping halves:
let (first_half, second_half) = scores.split_at_mut(3);
first_half[0] += 5;
second_half[0] += 50;
println!("first_half: {first_half:?}");
println!("second_half: {second_half:?}");
println!("scores: {scores:?}");
}
first_half: [15, 20, 30]
second_half: [90, 50, 60]
scores: [15, 20, 30, 90, 50, 60]