What is reborrowing?
Short answer: Passing a &mut to something that expects a &mut doesn’t move it. The compiler
reborrows — it writes &mut *r for you, a fresh borrow of the value the reference points at, lasting
for the call and no longer. The binding you passed is still there afterwards.
The borrow you didn’t write
Section titled “The borrow you didn’t write”From a fresh project — cargo new reborrow-demo, then replace src/main.rs with the whole of this.
The project name doesn’t matter, because nothing in the output depends on it:
fn bump(x: &mut i32) { *x += 1;}
fn main() { let mut value = 5; let r = &mut value;
bump(r); *r += 1;
println!("{r}");}7r is used after the call, and the file compiles. A &mut i32 is not Copy, so if bump(r) moved
it, the next line would be an error. What the compiler does instead is treat r as a place and
reborrow through it: the call is really bump(&mut *r). That new reference points at value, lives
for the duration of the call, and ends when bump returns. r is then a &mut i32 to the same
value again — hence *r += 1 lands and the print shows 7. Nothing in the source marks any of this;
reborrowing has no syntax.
Where it doesn’t happen
Section titled “Where it doesn’t happen”The reborrow appears where the expected type is a reference. Assign the reference to another binding
— let r2 = r; — and that is a plain move, because &mut i32 doesn’t implement Copy. The same
goes for anything that takes the reference by value, and a generic parameter is the usual way to
meet one:
fn take_anything<T>(_value: T) {}
fn main() { let mut value = 5; let r = &mut value;
take_anything(r); *r += 1;
println!("{r}");}error[E0382]: use of moved value: `r` --> src/main.rs:8:5 |5 | let r = &mut value; | - move occurs because `r` has type `&mut i32`, which does not implement the `Copy` trait6 |7 | take_anything(r); | - value moved here8 | *r += 1; | ^^^^^^^ value used here after move |help: consider creating a fresh reborrow of `r` here |7 | take_anything(&mut *r); | +++++++
For more information about this error, try `rustc --explain E0382`.At the call site the type of T isn’t known yet, so there is no reference type to reborrow through
and r moves. The compiler’s suggestion names the fix: write the reborrow yourself.
fn take_anything<T>(_value: T) {}
fn main() { let mut value = 5; let r = &mut value;
take_anything(&mut *r); *r += 1;
println!("{r}");}6&mut *r is the reborrow the compiler writes for you at a call site, now by hand: it borrows
value again for the length of the call, and r is untouched.
The rules still apply
Section titled “The rules still apply”A reborrow is an ordinary borrow, so exclusivity covers it too. Hand the same reference to a function twice and both arguments try to reborrow the same value:
fn bump_twice(a: &mut i32, b: &mut i32) { *a += 1; *b += 1;}
fn main() { let mut value = 5; let r = &mut value;
bump_twice(r, r);
println!("{r}");}error[E0499]: cannot borrow `*r` as mutable more than once at a time --> src/main.rs:10:19 |10 | bump_twice(r, r); | ---------- - ^ second mutable borrow occurs here | | | | | first mutable borrow occurs here | first borrow later used by call
For more information about this error, try `rustc --explain E0499`.The complaint is about *r — the value — not about the reference. Two exclusive borrows of value
overlap for the length of the call, which is what the rules of
borrowing refuse when you write &mut value
twice. Reborrowing is a convenience, not a loophole.
Where you already rely on it
Section titled “Where you already rely on it”Method calls reborrow too. A &mut self method called through a reference borrows the receiver for
the call and hands it back:
fn main() { let mut scores = vec![1, 2, 3]; let r = &mut scores;
r.push(4); r.push(5);
println!("{r:?}");}[1, 2, 3, 4, 5]If r.push(4) moved r, the second call couldn’t compile. Every chain of mutations through one
&mut — and every mem::swap(ra, rb) between two of them — works because each call reborrows and
returns the reference. Storing the reference in a struct field reborrows the same way: the field
holds a borrow of the value, and r is usable again once the struct is done with it.
Related
Section titled “Related”- What are the rules of borrowing? — the rules a reborrow obeys
- What is the difference between & and &mut? — the two kinds of borrow
- What is the borrow checker? — the pass that works out where the reborrows go
- How to borrow a value — the
&that starts all of this - Borrowing — the rest of this chapter
- Next in this chapter: how long does a borrow last?