References and Borrowing

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):

  1. No other &mut T reference to the same value can be created (E0499).
  2. No shared &T reference to the same value can be created (E0502).
  3. 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]