Ownership and Move Semantics¶
Rust's ownership system is its defining feature - a compile-time mechanism for memory safety without garbage collection. Three rules govern how values are created, transferred, and destroyed, eliminating use-after-free, double-free, and data races at compile time.
Key Facts¶
- Three ownership rules: (1) every value has an owner, (2) one owner at a time, (3) when owner goes out of scope, value is destroyed (
Drop::dropcalled) - Move is a bitwise copy from old to new location (may be elided by compiler); old value becomes inaccessible
- Clone = explicit deep copy via
.clone(), can be expensive - Copy = implicit bitwise copy, only for stack-only types (no heap allocations)
- RAII: resource acquisition tied to initialization, release tied to destruction
Memory Types¶
| Stack | Heap | |
|---|---|---|
| Contents | Local variables | Program data |
| Size | Limited (2-8 MB/thread) | Unlimited |
| Allocation speed | Fast | Slow |
| Size knowledge | Must know at compile time | Can be dynamic |
| Per-thread | One per thread | One per process |
Patterns¶
Move Semantics¶
let s1 = String::from("hello");
let s2 = s1; // s1 is MOVED to s2, s1 is now invalid
// println!("{}", s1); // ERROR: value used after move
let s1 = String::from("hello");
let s2 = s1.clone(); // deep copy, both valid
Move happens on: variable reassignment, passing by value to function, returning from function.
RAII¶
{
let string = String::from("Hello"); // allocation
println!("{}", string); // use
} // automatic deallocation (drop)
Resource management approaches: explicit (C), automatic (GC languages), semi-automatic (Rust RAII, Go defer, Python with).
Copy vs Clone¶
// Copy types: integers, floats, bool, char, tuples of Copy types
let x = 5;
let y = x; // Copy - both valid
println!("{} {}", x, y);
// Non-Copy types: String, Vec, Box - must use .clone() or move
let v1 = vec![1, 2, 3];
let v2 = v1.clone(); // explicit deep copy
Gotchas¶
- Integer overflow: debug mode panics, release mode wraps (two's complement); use
checked_add(),wrapping_add(),saturating_add()for explicit behavior let x = 5; let x = 5;is shadowing (new variable), not reassignment - different memory addressesusizeis the only valid type for array/slice indexing
See Also¶
- [[borrowing-and-references]] - non-owning access to data
- [[smart-pointers]] - Box, Rc, Arc for heap management
- [[lifetimes]] - compile-time tracking of reference validity