๐ฏ References and Borrowing in Rust
The Library Book Analogy ๐
Imagine you have a super special library book. In Rust, variables are like owning that book. But what if your friend wants to read it too? You have two choices:
- Give them the book (they own it now, you canโt use it!)
- Let them borrow it (they can read, but you still own it!)
This is exactly what References and Borrowing is all about!
๐ What is a Reference?
A reference is like giving someone your library card number instead of the actual book. They can look at the book, but you still own it!
fn main() {
let book = String::from("Harry Potter");
// Create a reference with &
let book_ref = &book;
println!("I still have: {}", book);
println!("Friend sees: {}", book_ref);
}
๐ Key Point
- The
&symbol creates a reference - The original variable (
book) keeps ownership - The reference (
book_ref) can read the data
graph TD A["book owns the data"] --> B["&book = reference"] B --> C["book_ref points to book"] C --> D["Both can read!"]
๐ค What is Borrowing?
Borrowing is the act of creating a reference. When a function โborrowsโ data, it uses a reference instead of taking ownership.
Without Borrowing (Ownership Moves) โ
fn print_book(s: String) {
println!("{}", s);
}
fn main() {
let book = String::from("Rust Book");
print_book(book);
// ERROR! book moved away!
// println!("{}", book);
}
With Borrowing (Reference) โ
fn print_book(s: &String) {
println!("{}", s);
}
fn main() {
let book = String::from("Rust Book");
print_book(&book);
// Works! We still own book!
println!("{}", book);
}
๐จ Think of it like this:
| Action | Real Life | Rust |
|---|---|---|
| Give book | Friend takes it | fn foo(s: String) |
| Lend book | Friend borrows | fn foo(s: &String) |
โ๏ธ Mutable References
What if your friend wants to write notes in your book? You need to give them special permission!
A mutable reference lets the borrower change the data.
fn main() {
// Must be 'mut' to allow changes
let mut book = String::from("Chapter 1");
// Mutable reference with &mut
add_chapter(&mut book);
println!("{}", book);
// Prints: Chapter 1, Chapter 2
}
fn add_chapter(s: &mut String) {
s.push_str(", Chapter 2");
}
๐ Two Types of References
| Type | Symbol | Can Read? | Can Write? |
|---|---|---|---|
| Immutable | & |
โ Yes | โ No |
| Mutable | &mut |
โ Yes | โ Yes |
graph TD A["Reference Types"] --> B["&T = Read Only"] A --> C["&mut T = Read + Write"] B --> D["Many can exist at once"] C --> E["Only ONE at a time!"]
๐ The Reference Rules
Rust has very important rules to keep your data safe. Think of them like library rules!
Rule 1: One Writer OR Many Readers
At any time, you can have:
- โ
Many immutable references (
&T), OR - โ
One mutable reference (
&mut T) - โ Never both at the same time!
fn main() {
let mut data = String::from("hello");
// Many readers? OK!
let r1 = &data;
let r2 = &data;
println!("{} {}", r1, r2);
// One writer? OK!
let w1 = &mut data;
w1.push_str(" world");
}
Why This Rule Exists ๐ค
Imagine two friends writing in your book at the same timeโchaos! Rust prevents this at compile time.
// This will NOT compile!
fn main() {
let mut s = String::from("hi");
let r1 = &s; // Reader 1
let w1 = &mut s; // Writer - ERROR!
println!("{}", r1);
}
Rule 2: References Must Be Valid
A reference must always point to valid data. Rust checks this for you!
โ ๏ธ Dangling References
A dangling reference is like a library card pointing to a book thatโs been thrown away. It points to nothing!
The Problem
// This will NOT compile!
fn dangle() -> &String {
let s = String::from("hello");
&s // s is destroyed here!
} // Reference points to nothing!
๐ก๏ธ Rust Saves You!
Rust refuses to compile dangling references. Youโll never have a crash from this bug!
The Fix
Instead of returning a reference, return the owned value:
fn no_dangle() -> String {
let s = String::from("hello");
s // Return ownership, not reference!
}
graph TD A["Function creates String"] --> B["Function ends"] B --> C{What to return?} C --> D["&String = DANGER!<br/>Data is gone!"] C --> E["String = SAFE!<br/>Ownership moves out"] D --> F["โ Compile Error"] E --> G["โ Works!"]
๐ฏ Quick Summary
| Concept | What It Means | Symbol |
|---|---|---|
| Reference | Borrow without owning | & |
| Borrowing | Using a reference | &variable |
| Mutable Ref | Borrow + can change | &mut |
| Rules | 1 writer OR many readers | - |
| Dangling | Invalid reference | Compiler stops it! |
๐ Why This Matters
With these rules, Rust guarantees:
- โ No data races
- โ No use-after-free bugs
- โ No null pointer crashes
- โ Memory safety without garbage collection!
Youโre now a borrowing expert! ๐
The compiler is your friendโit catches these bugs before your code ever runs!
