🎓 A1Learner
🔍

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 it

The 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?