Today, I went deep into one of Rust’s core ideas: Ownership. It’s a big reason Rust can guarantee memory safety without a garbage collector. I also learned how borrowing and the borrow checker work together with ownership to prevent bugs at compile time.
If you're coming from a JavaScript or TypeScript background like me, these ideas feel very different—but incredibly powerful.
🔐 What is Ownership?
Ownership in Rust is about managing memory safely and automatically. Instead of having a garbage collector or manual free()
calls like in C, Rust uses ownership rules enforced by the compiler to decide:
- Who owns a value
- When it should be cleaned up
- Who is allowed to use it
🧨 Safety = Absence of Undefined Behavior
Rust defines "safe" as not having undefined behavior. That means your code won’t crash randomly or behave unpredictably, especially around memory. Ownership helps Rust catch potential memory issues at compile time.
🎯 Ownership as a Discipline
- Every piece of heap data must have one and only one owner.
- When that owner goes out of scope, Rust automatically frees the memory.
- This ensures no memory leaks, no double frees, no use-after-free bugs.
🗂️ Stack vs Heap
- Stack: Stores fixed-size, known-at-compile-time data. Fast to access.
-
Heap: Stores dynamically sized data like
String
orVec
. Managed via ownership.
let x = 5; // stored on the stack
let s = String::from("hello"); // heap-allocated
📦 Boxes and Collections
Heap allocation is done via pointers like Box, or in collections like Vec, String.
These types own the heap memory and clean it up when they go out of scope.
🚫 No Manual Memory Management
Rust does not allow you to manually free memory. This removes an entire class of bugs. You just manage ownership — Rust handles cleanup.
🧳 Move Semantics
When you assign a variable to another, the ownership is moved, not copied.
let s1 = String::from("hello");
let s2 = s1; // s1 is now invalid
Using s1 after this causes a compile error, because s1 no longer owns the data.
📋 Cloning Avoids Moves
If you want to copy the data instead of moving it, use .clone():
let s1 = String::from("hello");
let s2 = s1.clone(); // s1 still valid
🔄 Variables Can't Be Used After Being Moved
This rule protects against dangling references and memory bugs:
let s1 = String::from("hello");
let s2 = s1;
// println!("{}", s1); // ❌ Compile error: s1 was moved
📎 References & Borrowing
A reference lets you access data without taking ownership.
&T is an immutable reference
&mut T is a mutable reference
fn print_length(s: &String) {
println!("Length: {}", s.len());
}
💡 References Are Non-Owning Pointers
They’re temporary and do not deallocate memory. You borrow the data, use it, and give it back.
🔍 Dereferencing Accesses the Data
Rust automatically dereferences when needed, but you can do it manually:
let x = 10;
let r = &x;
println!("Value: {}", *r); // dereference to get the value
🚫 No Aliasing & Mutation Simultaneously
Rust prevents data races at compile time by enforcing this rule:
You can either have multiple immutable references
OR one mutable reference — never both.
let mut s = String::from("hi");
let r1 = &s;
let r2 = &s;
// let r3 = &mut s; // ❌ Compile error
🔐 Borrowing Changes Permissions
Rust uses an RWO (Read / Write / Own) permission model internally:
- Read (R): Read the data
- Write (W): Mutate the data
- Own (O): Move or drop the data
Borrowing temporarily transfers permissions.
🕵️ Borrow Checker Finds Violations
Rust’s borrow checker is a tool in the compiler that ensures:
- No use-after-move
- No dangling pointers
- No simultaneous read/write to same data
🔁 Permissions Are Returned After Lifetime Ends
Once a reference goes out of scope, its permissions are returned to the original owner. You can then borrow again.
⌛ Data Must Outlive References
You cannot create a reference to data that goes out of scope.
let r;
{
let x = 5;
r = &x; // ❌ Error: `x` doesn't live long enough
}
📝 Summary – What I Learned
✅ Ownership guarantees memory safety without GC
✅ Heap data is automatically deallocated when its owner goes out of scope
✅ Move semantics prevent double frees
✅ Borrowing allows references, but with strict rules
✅ The borrow checker is your friend — not your enemy 😄
🔗 Follow me on Twitter: @subeshyadav
💬 Let's chat if you're learning Rust too!
Top comments (0)