References and Borrowing

Reborrowing

Reborrowing is the creation of a new, shorter-lived reference (&*r or &mut *r) from an existing reference r: &mut T. Because &mut T does not implement Copy, reborrowing is the mechanism that allows you to pass a mutable reference r: &mut T to multiple helper functions sequentially without moving and losing r on the very first call!

Why Reborrowing Exists

Remember that &mut T is not Copy. If you have r: &mut i32 and call a function increment(r), why doesn't increment(r) move r and prevent you from using r on the next line?

Because whenever you pass r: &mut T to a function parameter (or assign it to a variable with an explicit : &mut T type annotation), rustc automatically inserts an implicit reborrow (&mut *r)!

What You Write:                    What `rustc` Compiles (Implicit Reborrow):
  fn step(p: &mut i32) { *p += 1; }
  let r: &mut i32 = &mut x;
  step(r);                           step(&mut *r);  <-- Creates temporary sub-borrow `'sub`
  step(r);                           step(&mut *r);  <-- `r` was NOT moved; still usable!
fn add_five(target: &mut i32) {
    *target += 5;
}

fn main() {
    let mut score = 10;
    let r: &mut i32 = &mut score;

    // Implicitly reborrows `r` as `&mut *r` for the duration of `add_five`:
    add_five(r);
    // Because `r` was reborrowed rather than moved, we can still use `r`!
    add_five(r);
    *r += 2;

    println!("Final score via r: {r}");
}
Final score via r: 22

How the Borrow Stack Works During a Reborrow

You can think of borrows as a stack:

  1. let r1 = &mut x; places r1 at the top of the borrow stack (x is suspended while r1 is active).
  2. let r2 = &mut *r1; (or let r2: &mut i32 = r1;) reborrows from r1, placing r2 on top of r1 (r1 is temporarily suspended while r2 is active!).
  3. Once r2's last use finishes, r2 pops off the borrow stack and r1 becomes active again!
Stack of Active Mutable Borrows:
  Owner `x` ──(borrowed by)──> `r1: &mut i32` ──(reborrowed by)──> `r2: &mut i32` (Active top!)
  (While `r2` is active, neither `x` nor `r1` can be used; once `r2` ends, `r1` resumes!)
fn main() {
    let mut value = 100;
    let r1: &mut i32 = &mut value;

    {
        // Explicit reborrow `&mut *r1` (or `let r2: &mut i32 = r1;`):
        let r2 = &mut *r1;
        *r2 += 50;
        println!("Used reborrow r2: {r2}");
    } // `r2` ends here; `r1` is unsuspended!

    *r1 += 10;
    println!("Used r1 after r2 ended: {r1}");
}
Used reborrow r2: 150
Used r1 after r2 ended: 160

Implicit Reborrow (let r2: &mut T = r1;) vs Move (let r2 = r1;)

Notice a subtle rule when assigning a mutable reference variable r1 to a new variable r2:

  • Without a type annotation (let r2 = r1;): Performs a move of r1 into r2 (r1 is permanently invalidated!).
  • With a type annotation (let r2: &mut i32 = r1;) or explicit &mut *r1: Performs a reborrow of r1 (r1 is usable again as soon as r2's lifetime ends!).

Reborrowing &mut T as an Immutable &T (&*r)

You can also reborrow a mutable reference r: &mut T as a shared immutable reference &T (either explicitly via &*r or implicitly by passing r to a function expecting &T). While the shared reborrow &*r is active, r is temporarily frozen for reading only, and regains full mutable power once the shared reborrow ends.