What is borrowing in Rust and how do references work?
Learn how borrowing and references work in Rust — shared vs mutable references, the borrow checker, and how they prevent data races, with clear code examples.
Expected Interview Answer
Borrowing is accessing a value through a reference without taking ownership of it, letting code read or modify data while the original owner keeps responsibility for freeing it.
References come in two forms: shared/immutable references (&T), of which you can have many at once, and mutable references (&mut T), of which you can have only one at a time. The borrow checker enforces that you cannot have a mutable reference simultaneously with any other reference to the same data, which prevents data races and aliasing bugs at compile time. References must never outlive the data they point to, a constraint the compiler verifies through lifetimes.
- Access data without transferring ownership
- Multiple readers allowed via shared references
- Exclusive mutation guaranteed by a single mutable reference
- Prevents data races at compile time
- No copying or cloning overhead
AI Mentor Explanation
Borrowing is like players consulting the shared scoreboard: any number can read it at once without disturbing the game. But only the official scorer may update it, and while they are writing, no one else edits it — otherwise the score would become inconsistent. Many readers or one writer, never both: that is exactly Rust's rule for shared versus mutable references to the same data.
Step-by-Step Explanation
Step 1
Create a shared reference
Use &value to borrow immutably; the owner keeps ownership and you get read-only access.
Step 2
Allow many readers
Any number of shared references (&T) can coexist because none of them can mutate the data.
Step 3
Create a mutable reference
Use &mut value to borrow for modification; this requires the value binding itself to be mutable.
Step 4
Enforce exclusivity
While a &mut T exists, no other reference — shared or mutable — to that data is allowed, preventing races.
Step 5
Respect lifetimes
A reference must not outlive the data it points to; the borrow checker verifies this at compile time.
What Interviewer Expects
- Defining borrowing as access without ownership transfer
- Distinguishing &T (many) from &mut T (exactly one)
- Explaining the no-aliasing-with-mutation rule
- Connecting borrowing to data-race prevention
- Awareness that references cannot outlive their data (lifetimes)
Common Mistakes
- Thinking you can have a mutable and shared reference at the same time
- Believing borrowing takes ownership
- Allowing two mutable references to the same value
- Returning a reference to a local variable that goes out of scope
Best Answer (HR Friendly)
“Borrowing lets Rust code use data through a reference without owning it, so the original variable stays in charge of cleanup. You can have many read-only borrows or a single read-write borrow — never both at once — which is how Rust stops two parts of a program from corrupting the same data.”
Code Example
fn main() {
let mut v = vec![1, 2, 3];
let r1 = &v; // shared borrow
let r2 = &v; // another shared borrow is fine
println!("{:?} {:?}", r1, r2);
let m = &mut v; // exclusive mutable borrow (r1, r2 no longer used)
m.push(4);
println!("{:?}", m);
}Follow-up Questions
- Why can you have many shared references but only one mutable reference?
- What is a lifetime and how does it relate to borrowing?
- What is a dangling reference and how does Rust prevent it?
- How does the borrow checker enable fearless concurrency?
MCQ Practice
1. Which combination of references to the same data does Rust allow?
Rust permits many shared (&T) references at once, or exactly one mutable (&mut T) reference — but never a mutable alongside any other reference.
2. What does the borrow checker prevent at compile time?
By forbidding a mutable reference to coexist with any other reference, the borrow checker eliminates data races before the program runs.
Flash Cards
What is borrowing? — Accessing a value through a reference without taking ownership; the original owner remains responsible for freeing it.
Shared vs mutable references? — &T: many allowed, read-only. &mut T: exactly one allowed, exclusive, and never alongside any other reference.
What rule prevents data races? — A mutable reference cannot coexist with any other reference to the same data — enforced by the borrow checker.
What is a lifetime? — A compile-time guarantee that a reference never outlives the data it points to, preventing dangling references.