Mutable References
A mutable reference (also called an exclusive reference), written &mut T, is a pointer that borrows temporary read and write access to a value of type T without taking ownership of it. To prevent data races, iterator invalidation, and aliasing bugs, Rust enforces a strict rule: at most one active &mut T reference to a given value may exist at a time, and no shared &T references may coexist with it.
Creating and Using a Mutable Reference
To create a mutable reference &mut T:
- The owner variable itself must be declared mutable (
let mut x = ...;). - Borrow the variable using
&mut x. - Inside the borrower, mutate the value either via method calls (such as
r.push(...), which auto-dereferencesr) or via the explicit dereference operator (*r = new_val):
fn normalize_and_append(buffer: &mut String, suffix: &str) {
// 1. Mutating methods auto-dereference `buffer: &mut String`:
*buffer = buffer.trim().to_lowercase();
buffer.push_str(suffix);
}
fn increment_in_place(counter: &mut i32) {
// 2. Explicit `*` dereference on primitive value:
*counter += 1;
}
fn main() {
let mut name = String::from(" FERRIS_THE_CRAB ");
let mut visits = 0;
normalize_and_append(&mut name, "_2024");
increment_in_place(&mut visits);
increment_in_place(&mut visits);
println!("name = '{name}', visits = {visits}");
}
name = 'ferris_the_crab_2024', visits = 2
Why &mut T Is Called an "Exclusive Reference"
In Rust, &mut T means more than just "this pointer can write to T." It guarantees exclusive access: while a &mut T reference is active, no other reference (&T or &mut T) and not even the original owner variable itself is allowed to read or write that value until the mutable borrow ends!
While `let r: &mut Vec<i32> = &mut v;` is active:
+---------------+ +-------------------+
| v (Owner) | | r: &mut Vec<i32> |
| [Temporarily | | [SOLE active path |
| inaccessible]| | to read or write]|
+---------------+ +---------+---------+
│
v
[ Heap Vector Buffer ]
Because &mut T guarantees uniqueness, &mut T does NOT implement the Copy trait! If &mut T were Copy, assigning let r2 = r1; would create two simultaneous mutable aliases to the same memory location. Instead, assigning let r2 = r1; moves (or reborrows) the mutable reference.
Sequential Mutable Borrows (One After Another)
Although you cannot hold two active &mut references to the same variable at the same time, you can create as many &mut references as you want sequentially—as long as each earlier &mut reference is no longer used before the next one is created:
fn main() {
let mut balance = 100;
let first_borrow: &mut i32 = &mut balance;
*first_borrow += 50;
println!("After first_borrow: {first_borrow}");
// `first_borrow` is never used again below this line, so its lifetime ends here!
let second_borrow: &mut i32 = &mut balance;
*second_borrow -= 30;
println!("After second_borrow: {second_borrow}");
println!("Final balance: {balance}");
}
After first_borrow: 150
After second_borrow: 120
Final balance: 120
Swapping and Taking Values Through &mut T (std::mem)
Remember that you cannot move ownership out of *r directly (let x = *r; fails with E0507 if T is not Copy), because doing so would leave the borrowed owner's memory slot uninitialized.
However, because &mut T has exclusive write access, the std::mem module provides three safe, zero-allocation functions that extract an owned value from &mut T while immediately putting a valid replacement value in its place:
| Function | Signature | What It Does |
|---|---|---|
std::mem::swap(a, b) |
fn swap<T>(x: &mut T, y: &mut T) |
Exchanges the values at x and y in place without cloning or deallocating |
std::mem::replace(dest, src) |
fn replace<T>(dest: &mut T, src: T) -> T |
Writes src into *dest and returns the old value of *dest as an owned T |
std::mem::take(dest) |
fn take<T: Default>(dest: &mut T) -> T |
Replaces *dest with T::default() (such as an empty String or Vec) and returns the old owned T |
use std::mem;
fn drain_message(slot: &mut String) -> String {
// Takes ownership of the String inside `*slot` and leaves `String::new()` in its place:
mem::take(slot)
}
fn main() {
let mut inbox = String::from("Urgent notification");
let taken: String = drain_message(&mut inbox);
println!("Taken owned string: '{taken}'");
println!("Inbox after take: '{inbox}' (len = {})", inbox.len());
let previous = mem::replace(&mut inbox, String::from("New message"));
println!("Replaced '{previous}' with '{inbox}'");
}
Taken owned string: 'Urgent notification'
Inbox after take: '' (len = 0)
Replaced '' with 'New message'
Common Compiler Errors with &mut T
Two Simultaneous Mutable Borrows (E0499)
// ❌ does not compile
fn main() {
let mut data = vec![1, 2, 3];
let r1 = &mut data;
let r2 = &mut data;
r1.push(4);
r2.push(5);
}
error[E0499]: cannot borrow `data` as mutable more than once at a time
--> src/main.rs:5:14
|
4 | let r1 = &mut data;
| --------- first mutable borrow occurs here
5 | let r2 = &mut data;
| ^^^^^^^^^ second mutable borrow occurs here
6 |
7 | r1.push(4);
| -- first borrow later used here
error: aborting due to 1 previous error
Reading the Owner While a Mutable Borrow Is Still Active (E0502)
Even reading data via println!("{data:?}") temporarily borrows &data. Doing so while r1: &mut Vec<i32> is still alive and used on a later line violates r1's exclusivity:
// ❌ does not compile
fn main() {
let mut count = 10;
let r = &mut count;
println!("Reading owner directly while `r` is active: {count}");
*r += 1;
}
error[E0502]: cannot borrow `count` as immutable because it is also borrowed as mutable
--> src/main.rs:5:59
|
3 | let r = &mut count;
| ---------- mutable borrow occurs here
4 |
5 | println!("Reading owner directly while `r` is active: {count}");
| ^^^^^^^ immutable borrow occurs here
6 | *r += 1;
| ------- mutable borrow later used here
error: aborting due to 1 previous error