Rust Reborrowing
Reborrowing is a fresh, short borrow made through an existing reference. The original reference stays usable after the call.
Passing a &mut does not spend it
add_one takes a &mut i32. Calling it twice with the same r works, because neither call takes r itself:
add_one(r);
add_one(r); // r still works: each call reborrowed itThe star makes it visible
Writing the reborrow by hand shows what the calls above did silently. *r follows r to the value, and &mut borrows that value afresh:
add_one(&mut *r);A child borrow freezes the parent
While a reborrow is still going to be used, its parent is off limits:
let child = &mut *r;
*r += 1; // error E0503: *r was mutably borrowed by child
*child += 1;The parent wakes when the child ends
Once the child has had its last use, the parent is free again — the same non-lexical rule as any borrow:
let child = &mut *r;
*child += 1;
// child's last use is above, so r is free again
*r += 10;Borrow back down to a shared reference
A &mut may lend out a plain read-only view of what it points at. While that view is in use the parent waits, just as with any borrow:
let snapshot: &i32 = &*r;
println!("snapshot = {}", snapshot);Example
fn add_one(n: &mut i32) {
*n += 1;
}
fn main() {
let mut total = 10;
let r = &mut total;
add_one(r);
add_one(r);
add_one(&mut *r);
let snapshot: &i32 = &*r;
println!("snapshot = {}", snapshot);
*r += 100;
println!("total = {}", total);
}Key points
- Reborrow: a new, shorter borrow made through an existing reference, written &mut *r or &*r
- Every time you pass a &mut to a function, Rust silently reborrows it.
- That is why the original survives the call.
- A reborrow freezes its parent while it is live.
- The parent cannot be used until the child's last use.
- Trying is error E0503.
- A reborrow may be shorter than its parent, never longer: it cannot outlive the reference it was made through
- A &mut can also reborrow as a shared &: that view is read-only, like every &
In this example, total starts at 10 and r borrows it mutably. add_one is called with r twice. Each call reborrows r. It adds 1 through the child borrow and hands control back. So r survives both calls. The third call writes the reborrow out loud, as &mut *r, and adds 1 more. A shared reborrow, &*r, then takes a read-only snapshot, which prints 13. The snapshot is never used again. So r wakes up and adds 100 through *r. The last line prints total = 113.
Note
Reborrows stack like a pile of plates — last made, first finished.
Rust tracks the whole stack, so nested helper calls through one &mut simply work.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
You call add_one(r) twice with the same &mut r, and r still works afterwards. Why?