Ownership is Rust’s memory management system based on three rules:
each value has a single owner, only one owner can exist at a time, and a value is dropped when its owner goes out of scope.
Values are either moved (ownership is transferred) or copied (for simple Copy types like integers).
This system allows Rust to guarantee memory safety at compile time, without a garbage collector.
Value is dropped when its owner goes out of scope
fn main() {
let name = String::from("Pixy");
take_ownership(name);
}
fn take_ownership(s: String) {
println!("{}", s);
} // s goes out of scope here → dropped
Here, ownership of name is moved into take_ownership.
When the function ends, s goes out of scope and Rust automatically frees the memory.
Ownership is transferred (moved)
fn main() {
let username = String::from("Pixy");
print_user(username);
}
fn print_user(name: String) {
println!("User: {}", name);
}
Passing username into print_user moves ownership.
After the move, main can no longer access username. Only one owner exists at a time.
Function takes ownership
fn take(s: String) {
println!("{}", s);
}
fn main() {
let name = String::from("Pixy");
take(name);
}
The function parameter s becomes the new owner.
Once take finishes, the value is dropped.
Borrowing with immutable references
fn borrow(s: &String) {
println!("{}", s);
}
fn main() {
let name = String::from("Pixy");
borrow(&name);
println!("{}", name);
}
Here, the function borrows name using &String.
Ownership stays in main, so name is still usable afterward.
Multiple immutable references at the same time
Rust allows multiple immutable references to the same value at the same time, as long as no one is mutating it.
fn main() {
let name = String::from("Pixy");
let ref1 = &name;
let ref2 = &name;
println!("{} {}", ref1, ref2);
}
This works because:
- Both
ref1andref2are read-only - Ownership still stays with
name - No data race is possible when only reading
Borrowing rule summary
- ✅ Multiple immutable references are allowed
- ✅ One mutable reference is allowed
- ❌ Mutable and immutable references cannot coexist
This rule is what lets Rust be strict and flexible at the same time.
Borrowing with mutable references
fn change(s: &mut String) {
s.push_str("!");
}
fn main() {
let mut name = String::from("Pixy");
change(&mut name);
}
Mutable borrowing allows modifying a value without taking ownership.
Rust ensures only one mutable reference exists at a time, preventing data races.
Final thought
Ownership, moves, and borrowing work together to prevent memory leaks, use-after-free errors, and data races — all without runtime overhead.
Top comments (0)