The Ownership Rules
Ownership is Rust's most unique feature and enables memory safety without a garbage collector. Three rules govern ownership:
- Each value has exactly one owner (a variable)
- When the owner goes out of scope, the value is dropped (freed)
- There can only be one owner at a time
fn main() {
let s1 = String::from("hello");
let s2 = s1; // s1 is MOVED to s2
// println!("{}", s1); // ❌ s1 no longer valid!
println!("{}", s2); // ✅ "hello"
}
Clone — deep copy
let s1 = String::from("hello");
let s2 = s1.clone(); // explicit deep copy
println!("{} and {}", s1, s2); // both valid
Borrowing with References
References allow you to refer to a value without taking ownership:
fn calculate_length(s: &String) -> usize {
s.len() // borrow only, no ownership transfer
}
let s1 = String::from("hello");
let len = calculate_length(&s1); // pass reference
println!("Length of '{}' is {}", s1, len); // s1 still valid
Mutable References
fn change(s: &mut String) {
s.push_str(", world");
}
let mut s = String::from("hello");
change(&mut s);
println!("{}", s); // "hello, world"
// Rules: only ONE mutable reference at a time
// and no mutable + immutable refs simultaneously
Slices
let s = String::from("hello world");
let hello = &s[0..5]; // slice: "hello"
let world = &s[6..11]; // slice: "world"
println!("{} {}", hello, world);
// Array slices
let arr = [1, 2, 3, 4, 5];
let slice = &arr[1..3]; // [2, 3]
println!("{:?}", slice);