Skip to content

Ownership & Borrowing

Rust’s most distinctive feature is its ownership system — a set of rules the compiler enforces at compile time to guarantee memory safety without a garbage collector.

Every piece of memory in a Rust program is owned by exactly one variable at any given moment. When that variable goes out of scope, Rust automatically frees the memory. There is no runtime bookkeeping, no GC pauses, and no possibility of use-after-free or double-free bugs — the compiler rules them out entirely.

  1. Every value in Rust has exactly one owner.
  2. When the owner goes out of scope, the value is dropped (memory is freed).
  3. Ownership can be transferred (moved) to a new owner — at which point the old owner is no longer valid.

These three rules are the entire foundation. Everything else in this module — moves, references, mutable borrows, and slices — flows from them.

fn main() {
// Rule 1: one owner
let s = String::from("hello");
// Rule 2: out of scope → dropped
{
let inner = String::from("inner");
println!("{}", inner);
} // inner is freed here
// Rule 3: ownership transferred to t
let t = s;
println!("{}", t);
// s is no longer valid here
}
LessonConcept
Ownership & MovesEach value has one owner; assignment moves non-Copy types
References & BorrowingBorrow a value with &T without taking ownership
Mutable BorrowsModify through &mut T; the exclusive-access rule
SlicesBorrow a contiguous portion of a collection with &[T] or &str

A GC scans memory at runtime to find unreachable values and free them. This adds runtime overhead and introduces unpredictable pauses. Rust moves that work entirely to compile time: the compiler tracks every ownership transfer and scope exit and inserts the drop calls for you. The result is C-level performance with complete memory safety.

fn main() {
// Rule 1: every value has exactly one owner
let owner = String::from("owned by owner");
println!("Rule 1: {}", owner);
// Rule 2: when the owner goes out of scope, the value is dropped
{
let scoped = String::from("scoped value");
println!("Rule 2 inside scope: {}", scoped);
} // scoped is dropped here — memory is freed
println!("Rule 2: scoped is gone");
// Rule 3: ownership can be transferred (moved)
let new_owner = owner;
println!("Rule 3: now {}", new_owner);
// 'owner' is no longer valid here
}
How many owners can a value have at one time in Rust?
What happens to a value when its owner goes out of scope?
Which mechanism does Rust use to guarantee memory safety?