Rust's ownership system is one of its most distinctive features. It enables Rust to guarantee memory safety without needing a garbage collector. In this post, we'll explore how ownership works and why it's so powerful.
What is Ownership?
Ownership is a set of rules that governs how Rust manages memory. The core rules are:
The Three Rules of Ownership
- 1 Each value in Rust has an owner
- 2 There can only be one owner at a time
- 3 When the owner goes out of scope, the value is dropped
A Simple Example
Let's look at a basic example:
fn main() { let s = String::from("hello"); println!("{}", s); }
In this code,
s
is the owner of the String value. When
s
goes out of scope at the end of
main,
Rust automatically calls the
drop
function and the memory is freed.
Move Semantics
When you assign one variable to another, Rust moves the ownership:
fn main() { let s1 = String::from("hello"); let s2 = s1; // s1 is moved to s2 // println!("{}", s1); // This would cause a compile error! println!("{}", s2); // This works fine }
This prevents double-free errors that plague C and C++ programs.
Borrowing
If you want to use a value without taking ownership, you can borrow it:
fn main() { let s1 = String::from("hello"); let len = calculate_length(&s1); println!("The length of '{}' is {}.", s1, len); } fn calculate_length(s: &String) -> usize { s.len() }
The
&
symbol creates a reference that borrows the value without taking
ownership.
Mutable References
You can also have mutable references, but with restrictions:
fn main() { let mut s = String::from("hello"); change(&mut s); println!("{}", s); } fn change(s: &mut String) { s.push_str(", world"); }
The key restriction: you can have either one mutable reference OR any number of immutable references, but not both at the same time.
Why This Matters
Rust's ownership system prevents:
- Dangling pointers: References that point to freed memory
- Double frees: Freeing the same memory twice
- Data races: Multiple threads accessing the same data without synchronization
Key insight
All of these checks happen at compile time, with zero runtime overhead. You get the safety of a garbage-collected language with the performance of manual memory management.
Conclusion
Ownership is the foundation of Rust's memory safety guarantees. While it takes some getting used to, it eliminates entire classes of bugs that are common in other systems programming languages.
In future posts, we'll explore more advanced ownership patterns and how they enable safe concurrent programming.