The Three Ownership Rules
Stack vs Heap (Why Ownership Exists)
Returning Ownership
Borrowing (Using Without Owning)
Mutable Borrow (&mut)
Borrowing Rules (Very Important)
Prevents Use-After-Free Bugs (Automatically)
Eliminates Double Free Errors
No Null Pointer Crashes
Safe Sharing with Borrowing (Read vs Write)
Prevents Data Races at Compile Time
Automatic Memory Cleanup (Without Garbage Collector)
Ownership Makes Function Contracts Safer
Real-World Reliability Benefits
Ownership – Interview Questions & Answers
“Rust’s ownership system makes the language reliable by enforcing memory safety, preventing data races, and eliminating entire classes of runtime bugs at compile time—without using a garbage collector.”
The Three Ownership Rules
Rule 1️⃣: Each value has one owner
let s = String::from("hello");
Here, s is the owner of the string "hello".
Rule 2️⃣: There can be only one owner at a time
let s1 = String::from("hello");
let s2 = s1; // ownership moves to s2
// println!("{}", s1); ❌ error: s1 no longer valid
println!("{}", s2);
👉 Ownership moves, it does not copy (for heap data).
Rule 3️⃣: When the owner goes out of scope, the value is dropped
{
let s = String::from("hello");
} // s goes out of scope → memory is freed automatically
✔ No free()
✔ No garbage collector
✔ No memory leaks
Stack vs Heap (Why Ownership Exists)
Stack (Copied)
Simple types are stored on the stack and copied.
let x = 10;
let y = x;
println!("{}", x); // OK
Types that implement Copy:
integers
floats
bool
char
tuples of Copy types
Heap (Moved)
Complex types use heap memory and are moved.
let s1 = String::from("hello");
let s2 = s1; // move
// s1 is invalid here
Ownership with Functions
Passing Ownership
fn takes_ownership(s: String) {
println!("{}", s);
}
fn main() {
let s = String::from("hello");
takes_ownership(s);
// println!("{}", s); ❌ ownership moved
}
Returning Ownership
fn gives_ownership() -> String {
String::from("hello")
}
fn main() {
let s = gives_ownership(); // ownership received
}
Borrowing (Using Without Owning)
Ownership would be painful without borrowing.
Immutable Borrow (&)
fn print_length(s: &String) {
println!("{}", s.len());
}
fn main() {
let s = String::from("hello");
print_length(&s); // borrow
println!("{}", s); // still valid
}
✔ No ownership transfer
✔ Read-only access
Mutable Borrow (&mut)
fn add_text(s: &mut String) {
s.push_str(" world");
}
fn main() {
let mut s = String::from("hello");
add_text(&mut s);
println!("{}", s);
}
Borrowing Rules (Very Important)
You can have many immutable references
You can have only one mutable reference
Mutable and immutable references cannot coexist
❌ Invalid:
let mut s = String::from("hello");
let r1 = &s;
let r2 = &mut s; // error
✔ Prevents data races at compile time
Prevents Use-After-Free Bugs (Automatically)
In C/C++
free(ptr);
printf("%d", *ptr); // ❌ dangerous
In Rust
let s = String::from("hello");
drop(s);
// println!("{}", s); ❌ compile-time error
✅ Rust does not allow access to freed memory.
Result: No crashes, no undefined behavior.
2️⃣
Eliminates Double Free Errors
Problem in other languages
Memory freed twice → program crash or security issue
Rust
let s = String::from("data");
let t = s; // ownership moved
// s is now invalid
✅ Compiler guarantees memory is freed exactly once.
3️⃣
No Null Pointer Crashes
Rust does not allow null references.
let name: Option<String> = None;
You must explicitly handle:
match name {
Some(n) => println!("{}", n),
None => println!("No name"),
}
✅ Every possible state is handled
❌ No NullPointerException ever
4️⃣
Safe Sharing with Borrowing (Read vs Write)
Rust allows borrowing, but with strict rules:
Many immutable references OR
One mutable reference (never both)
let mut data = String::from("Rust");
let r1 = &data;
let r2 = &data; // ✅ allowed
// let r3 = &mut data; ❌ not allowed
Why this matters
Prevents race conditions
Prevents inconsistent state
5️⃣
Prevents Data Races at Compile Time
In most languages, concurrency bugs appear in production.
Rust:
use std::thread;
let v = vec![1, 2, 3];
thread::spawn(move || {
println!("{:?}", v);
});
✅ Compiler ensures:
Data is safely transferred
No shared mutable state
No locks required
Result: Fearless concurrency
6️⃣
Automatic Memory Cleanup (Without Garbage Collector)
Rust:
Frees memory deterministically
No GC pauses
No memory leaks
{
let file = File::open("data.txt");
} // file automatically closed here
✅ Faster, predictable backend systems
❌ No GC overhead like Java or Go
7️⃣
Ownership Makes Function Contracts Safer
fn process(data: String) {
// takes ownership
}
fn read(data: &String) {
// borrows
}
From the function signature alone, you know:
Who owns data
Whether it will be consumed
Whether mutation is allowed
👉 APIs become self-documenting and safe
Real-World Reliability Benefits
Ownership – Interview Questions & Answers
Basic Level
1. What is ownership in Rust?
Answer:
Ownership is Rust’s compile-time memory management system that ensures each value has a single owner, and memory is automatically freed when the owner goes out of scope—without a garbage collector.
2. Why does Rust use ownership?
Answer:
To prevent:
Dangling pointers
Double free errors
Data races
while maintaining high performance and memory safety.
3. What are the three ownership rules?
Answer:
Each value has one owner
Only one owner at a time
When the owner goes out of scope, the value is dropped
4. What happens when ownership is moved?
Answer:
The original variable becomes invalid and cannot be used.
let s1 = String::from("hi");
let s2 = s1;
// s1 is no longer valid
5. Which types follow the Copy trait?
Answer:
Simple stack-allocated types:
Integers
Floats
bool
char
Tuples of Copy types
Intermediate Level
6. What is the difference between move and copy?
Answer:
Move: Transfers ownership (heap data like String)
Copy: Duplicates value (stack data like i32)
7. What happens when a variable goes out of scope?
Answer:
Rust automatically calls drop, freeing the memory.
8. How does ownership work with functions?
Answer:
Passing a value transfers ownership unless it’s a Copy type or borrowed.
fn take(s: String) {}
9. What is borrowing?
Answer:
Borrowing allows using a value without taking ownership, using references (& or &mut).
10. What is immutable borrowing?
Answer:
Allows read-only access to a value without changing it.
fn read(s: &String) {}
Advanced Level
11. What is mutable borrowing?
Answer:
Allows modifying a value through a mutable reference.
fn change(s: &mut String) {
s.push_str("!");
}
12. What are Rust’s borrowing rules?
Answer:
Any number of immutable references or
Exactly one mutable reference
Mutable and immutable references cannot coexist
13. Why does Rust restrict multiple mutable references?
Answer:
To prevent data races at compile time.
14. What is a dangling reference?
Answer:
A reference to memory that has already been freed. Rust prevents this at compile time.
15. What is clone() and when should it be used?
Answer:
clone() performs a deep copy. Use it only when ownership duplication is truly required.
16. How is ownership different from garbage collection?
Answer:
Ownership frees memory deterministically at scope end, while GC frees memory at runtime unpredictably.
17. Can ownership be shared?
Answer:
Not directly. Sharing is done via:
Borrowing
Smart pointers (Rc, Arc) in advanced cases
18. How does ownership help concurrency?
Answer:
It prevents shared mutable state, eliminating data races at compile time.
19. Does Rust ever allow multiple owners?
Answer:
Only via smart pointers like Rc or Arc with explicit intent.
20. One-line ownership explanation for interviews?
Answer:
Ownership is Rust’s way of enforcing safe memory management at compile time without a garbage collector.
Part 2: MCQs on Ownership (With Answers)
MCQs – Basics
- What is the owner of a value in Rust?
A. Compiler
B. Memory allocator
C. Variable bound to the value
D. Function
✅ Answer: C
- What happens when ownership is moved?
A. Value is copied
B. Value is cloned
C. Original variable becomes invalid
D. Program panics
✅ Answer: C
- Which type does NOT implement Copy?
A. i32
B. bool
C. String
D. char
✅ Answer: C
- When is memory freed in Rust?
A. Manually
B. By garbage collector
C. When owner goes out of scope
D. At program end
✅ Answer: C
MCQs – Borrowing
- What symbol denotes borrowing?
A. *
B. &
C. %
D. @
✅ Answer: B
- How many mutable references are allowed at a time?
A. Unlimited
B. Two
C. One
D. Zero
✅ Answer: C
- Which combination is invalid?
A. Multiple immutable references
B. Mutable and immutable reference together
C. One mutable reference
D. Copy assignment
✅ Answer: B
MCQs – Advanced
- What does Rust prevent using ownership rules?
A. Memory leaks only
B. Stack overflow
C. Data races and dangling pointers
D. Logic errors
✅ Answer: C
- What does clone() do?
A. Shallow copy
B. Deep copy
C. Move ownership
D. Borrow value
✅ Answer: B
- Which feature enables safe concurrency?
A. Garbage collection
B. Mutex only
C. Ownership and borrowing
D. Thread sleep
✅ Answer: C
- Which ownership rule is violated here?
let r1 = &mut s;
let r2 = &mut s;
A. Multiple owners
B. Multiple mutable borrows
C. Dangling reference
D. Scope violation
✅ Answer: B
- What does drop do?
A. Moves value
B. Borrows value
C. Frees memory
D. Copies value
✅ Answer: C
- Ownership is checked at:
A. Runtime
B. Compile time
C. Link time
D. Execution end
✅ Answer: B
- Which allows shared ownership safely?
A. Box
B. Rc / Arc
C. String
D. Vec
✅ Answer: B
- Ownership is MOST important for:
A. UI apps
B. Scripts
C. Systems programming
D. Static websites
✅ Answer: C
Top comments (0)