In this tutorial, you’ll learn the differences between mutable and immutable references.
In Rust, you can borrow values instead of moving ownership:
&T→ Immutable reference (read-only).&mut T→ Mutable reference (read & write).
Both give you access to the same value without taking ownership.
Immutable References (&) #
By default, references are immutable:
fn main() {
let name = String::from("Alice");
let r1 = &name; // borrow immutably
let r2 = &name; // multiple immutable borrows are fine
println!("r1: {}, r2: {}", r1, r2);
println!("Original: {}", name); // still valid
}
Code language: Rust (rust)You can have any number of immutable references at the same time. But you cannot change through them.
Mutable References (&mut) #
If you want to modify the borrowed value, you need a mutable reference. For example:
fn main() {
let mut greeting = String::from("Hello");
change(&mut greeting); // borrow mutably
println!("Modified: {}", greeting);
}
fn change(s: &mut String) {
s.push_str(", world!");
}
Code language: Rust (rust)In this example:
let mut greetingmakes the variable itself mutable.&mut greetingallows the function to modify the string.- Ownership still stays in
main.
Borrowing Rules Enforced by Rust #
Rust prevents dangerous patterns by enforcing three simple rules at compile time:
1. You can have multiple immutable references:
let r1 = &text;
let r2 = &text;
// ✅ both fine
Code language: Rust (rust)2. You can have only one mutable reference at a time:
let r1 = &mut text;
let r2 = &mut text; // ❌ ERROR: cannot borrow `text` mutably more than once
Code language: Rust (rust)3. You cannot mix immutable and mutable references. For example, you cannot borrow text as mutable while also borrowed as immutable like this:
let r1 = &text;
let r2 = &mut text; // ❌ ERRORCode language: Rust (rust)It is because:
- Multiple immutable refs are safe → nothing changes.
- A single mutable ref is safe → only one place can modify at a time.
- Mixing would allow one part of your code to read while another is changing → data race.
Example: Compiler Enforces Safety #
fn main() {
let mut value = 42;
let r1 = &value; // immutable borrow
let r2 = &value; // immutable borrow
// let r3 = &mut value; // ❌ not allowed here
println!("r1: {}, r2: {}", r1, r2);
// After r1 and r2 are no longer used, mutable borrow is allowed
let r3 = &mut value;
*r3 += 1;
println!("r3: {}", r3);
}
Code language: Rust (rust)Rust tracks when references are last used, so it knows when it’s safe to create a mutable one.
Summary #
&T→ Immutable reference: many allowed, read-only.&mut T→ Mutable reference: only one allowed, read & write.- No mixing mutable + immutable references at the same time.
- Rust enforces these rules at compile time, preventing data races and memory bugs.