02. Ownership, Borrowing & Slices
Ownership is Rustโs most unique feature. It enables memory safety without a garbage collector or manual memory management.
Stack and Heap
Rust places data on the stack (fixed size, fast) or the heap (variable size, dynamic). The Ownership system governs how heap data is allocated and deallocated.
The Rules of Ownership
- Each value has an owner.
- There is only one owner at a time.
- When the owner goes out of scope, the value is dropped.
Move vs. Copy
When we assign one variable to another:
- Copy: Scalar types (integers, bools, etc.) that reside on the stack are copied.
- Move: Heap-allocated data (like
String) is moved. The original variable becomes invalid.
let s1 = String::from("hello");
let s2 = s1; // s1 is moved to s2. s1 is no longer valid.
// println!("{}", s1); // This would cause a compile-time error!Borrowing (References)
Instead of moving ownership, we can borrow a value using references (&).
fn calculate_length(s: &String) -> usize {
s.len()
} // s goes out of scope, but because it's a reference, nothing is dropped.The Two Rules of Borrowing
You can have either:
- Any number of immutable references (
&T). - Exactly one mutable reference (
&mut T).
Note: You cannot have a mutable reference while you have any immutable ones. This rule prevents Data Races at compile time.
Slices
Slices allow you to reference a contiguous sequence of elements in a collection rather than the entire collection.
let s = String::from("hello world");
let hello = &s[0..5];
let world = &s[6..11];Slices do not have ownership; they are essentially a pointer and a length.
Moving on to module 02, where we will build complex data structures with Structs and Enums.