title: Borrowing
Borrowing lets you use a value without taking ownership of it. You borrow a value by creating a reference with &.
Immutable references
let s = String::from("hello");
let r = &s; // borrow s
println!("{r}"); // works
println!("{s}"); // also works — s is still the ownerYou can have as many immutable references as you like at the same time.
Mutable references
Add mut to borrow mutably:
let mut s = String::from("hello");
let r = &mut s;
r.push_str(", world");
println!("{r}"); // "hello, world"The rules
The borrow checker enforces two rules at compile time:
- You can have any number of immutable references, OR exactly one mutable reference — never both at the same time
- References must always be valid (no dangling references)
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s; // fine — multiple immutable refs
let r3 = &mut s; // ERROR — can't have mutable ref while immutable refs exist
println!("{r1}, {r2}, {r3}");Why these rules?
The rules prevent data races at compile time:
- Multiple readers are safe — none can change the data
- A single writer is safe — nothing else is reading
- Both at once is undefined behaviour in other languages — Rust simply forbids it
Non-lexical lifetimes
References only need to follow the rules while they’re actually in use. Once a reference is last used, it’s considered dropped even if it’s still technically in scope:
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{r1}, {r2}"); // r1 and r2 last used here — effectively dropped
let r3 = &mut s; // fine now
println!("{r3}");Dangling references
Rust prevents you from returning a reference to a value that no longer exists:
fn dangle() -> &String { // ERROR
let s = String::from("hello");
&s // s is dropped at end of function — this reference would be invalid
}The fix is to return the owned value instead:
fn no_dangle() -> String {
let s = String::from("hello");
s // ownership is moved out, no problem
}