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:
let r1 = &mut x;placesr1at the top of the borrow stack (xis suspended whiler1is active).let r2 = &mut *r1;(orlet r2: &mut i32 = r1;) reborrows fromr1, placingr2on top ofr1(r1is temporarily suspended whiler2is active!).- Once
r2's last use finishes,r2pops off the borrow stack andr1becomes 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 ofr1intor2(r1is permanently invalidated!). - With a type annotation (
let r2: &mut i32 = r1;) or explicit&mut *r1: Performs a reborrow ofr1(r1is usable again as soon asr2'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.