Rust Borrowing
On the ownership page you saw a problem: passing a String to a function moves it, so you can’t use it afterward. Constantly moving values around (or cloning them) would be painful. Borrowing is Rust’s solution.
Borrowing means letting some code use a value without taking ownership of it — like lending a friend a book. They can read it, then give it back, and you still own it.
References: borrowing with &
Section titled “References: borrowing with &”You create a reference by putting & in front of a value. A reference lets a function look at the data without owning it:
fn print_length(s: &String) { // borrows s, doesn't own it println!("Length: {}", s.len());}
fn main() { let text = String::from("hello"); print_length(&text); // lend text to the function println!("Still mine: {text}"); // ✅ text is still valid here}Output:
Length: 5Still mine: helloThe &text says “let this function borrow text.” Because the function only borrowed it, ownership stays with main, and you can keep using text afterward. Compare this to the ownership page, where the same code without & caused an error.
Mutable references: borrowing to change
Section titled “Mutable references: borrowing to change”A plain & reference is read-only — you can look but not touch. If a function needs to change the borrowed value, use a mutable reference with &mut:
fn add_excitement(s: &mut String) { s.push_str("!!!");}
fn main() { let mut text = String::from("hello"); add_excitement(&mut text); // lend it mutably println!("{text}"); // hello!!!}Output:
hello!!!Notice three things had to line up: text is declared mut, the function asks for &mut String, and the call passes &mut text. All three are required to change a borrowed value.
The borrowing rules
Section titled “The borrowing rules”Rust enforces two rules about references. They exist to prevent data races — a whole class of bugs where two pieces of code touch the same data at the same time and corrupt it.
At any given time, you can have either:
- any number of read-only references (
&), or - exactly one mutable reference (
&mut),
but not both at once.
In plain English: many readers or one writer, never both together. This code breaks the rule:
fn main() { let mut text = String::from("hello");
let r1 = &text; // a read-only borrow let r2 = &mut text; // ❌ can't borrow mutably while r1 exists
println!("{r1} {r2}");}The compiler stops you:
error[E0502]: cannot borrow `text` as mutable because it is also borrowed as immutableWhy this matters
Section titled “Why this matters”These rules are checked entirely at compile time, so they cost nothing when your program runs. This is how Rust can promise “no data races” and still be as fast as C — the safety is proven before the program ever starts.
- Borrowing (
&) lets code use a value without taking ownership — you get it back. - A plain
&reference is read-only; use&mutto modify the borrowed value. - To mutate through a reference, the variable, the parameter, and the call all need
mut/&mut. - The rule: many readers or one writer, never both at once.
- All of this is checked at compile time, so it’s free at runtime.
Quick check
Section titled “Quick check”Quick check
1. What does putting `&` in front of a value do when passing it to a function?
2. According to the borrowing rules, which combination is allowed at the same time?
3. What do you need to modify a value through a reference?
4. Why can Rust enforce the borrowing rules without any runtime performance cost?
Score: 0 / 4