Rust Fundamentals: Ownership, Errors and Fearless Concurrency · Rust Basics and Ownership
Ownership: Rust's Superpower
Every value has one owner; when the owner goes out of scope the value is freed. Assigning or passing a String moves it, Copy types are duplicated, and clone makes an explicit deep copy. This is how Rust is memory-safe without a garbage collector.
What you'll build
A small playlist program that moves, copies and clones songs between variables and functions, so you can see exactly when a value can and can't be used.
The idea
Most languages either make you free memory yourself (C, C++) or use a garbage collector (Java, Go, Python). Rust uses ownership, checked at compile time:
- Each value has exactly one owner (a variable).
- When the owner goes out of scope, the value is dropped (freed).
- Assigning a heap value like
StringorVecto another variable, or passing it to a function, moves ownership. The old variable can no longer be used.
Simple fixed-size types (integers, floats, bool, char, and tuples of them) implement Copy: assigning them copies the bits, and both variables stay usable.
If you really want two independent heap values, call .clone(): an explicit, visible (and possibly expensive) deep copy.
Functions can give ownership back by returning a value. Passing ownership in and out everywhere is clumsy, though, which is why the next lesson introduces borrowing.
The code
fn describe(song: String) -> String {
// `song` is owned here; we return a new String (ownership of it goes to the caller)
format!("{} ({} chars)", song, song.len())
}
fn total_seconds(minutes: u32, seconds: u32) -> u32 {
minutes * 60 + seconds // u32 is Copy: callers keep their values
}
fn main() {
let favourite = String::from("Blue in Green");
let moved = favourite; // ownership moves to `moved`
// println!("{favourite}"); // error: value used after move
println!("moved: {moved}");
let copy_a = 5;
let copy_b = copy_a; // integers are Copy: both usable
println!("copies: {copy_a} and {copy_b}");
let original = String::from("So What");
let cloned = original.clone(); // explicit deep copy: two independent Strings
println!("original: {original}, clone: {cloned}");
let summary = describe(cloned); // `cloned` moves into the function...
println!("summary: {summary}"); // ...and we get a new String back
// println!("{cloned}"); // error: `cloned` was moved into describe()
let (m, s) = (9, 25);
println!("length: {}s, and m and s are still usable: {m}:{s}", total_seconds(m, s));
{
let temporary = String::from("dropped at the end of this block");
println!("{temporary}");
} // `temporary` goes out of scope here and its memory is freed automatically
}
Output
moved: Blue in Green copies: 5 and 5 original: So What, clone: So What summary: So What (7 chars) length: 565s, and m and s are still usable: 9:25 dropped at the end of this block
Run this on your computer — see “Get Started” for setup.
The commented-out lines are exactly what the compiler would reject, with errors like "borrow of moved value: favourite". Those errors are Rust stopping use-after-free and double-free bugs before your program runs.
Common mistakes
- Using a value after moving it. If you still need it, borrow it (next lesson) or
clone()it. - Cloning to silence the compiler. It works, but extra copies cost time and memory; first ask whether a borrow would do.
- Expecting
Stringto beCopy. Only fixed-size, stack-only types areCopy. - Thinking moves are expensive. A move copies a small pointer/length/capacity record, not the heap data.
Key points
- One owner per value; the value is dropped when its owner goes out of scope.
- Assigning or passing a
String/Vecmoves it; the old variable becomes unusable. Copytypes (numbers, bool, char) are duplicated instead of moved..clone()makes an explicit deep copy.
Further reading: What is ownership?
Practice questions
What are Rust's three ownership rules?
Answer
Each value has an owner; there can be only one owner at a time; when the owner goes out of scope, the value is dropped.
Why can you use an integer after assigning it to another variable but not a String?
Answer
Integers implement Copy, so assignment duplicates the value. String owns heap memory and isn't Copy, so assignment moves ownership and the original variable can't be used (preventing a double free).
Open in the app to mark lessons complete, take notes and track your progress.