Rust Ownership
This is the topic that makes Rust different from every language you may have seen before. Take it slowly, run every example, and break them on purpose to see what the compiler says. Once ownership clicks, the rest of Rust feels much friendlier.
Why ownership exists
Every program needs memory to store its values, and that memory must be given back when it is no longer needed. Some languages make you free memory by hand, which is easy to get wrong. Others run a garbage collector that cleans up from time to time, which costs speed. Rust takes a third path: it follows a few simple rules while compiling, and frees each value at exactly the right moment, with no extra work at run time.
The three rules
- Every value has one owner, a variable that is responsible for it.
- There is only one owner at a time.
- When the owner goes out of scope (its block of curly brackets ends), the value is dropped and its memory is freed.
Think of a library book with one borrower card. Whoever holds the card owns the book for now. You can hand the card to a friend, but then it is theirs, not yours. And when the last holder is done, the book goes back to the shelf.
Moving a value
Watch what happens when we give a String to another variable:
fn main() {
let a = String::from("hello");
let b = a;
println!("{} {}", a, b);
}error[E0382]: borrow of moved value: `a`
This program does not compile, on purpose. let b = a; does not copy the text. It moves ownership from a to b, like handing over the borrower card. After that, a is no longer allowed to use the value, and the compiler says so. Open it in the editor to see the full message; it even draws an arrow to the line where the move happened.
clone: when you really want two
If you need two independent copies, ask for one with clone:
fn main() {
let a = String::from("hello");
let b = a.clone();
println!("{} and {}", a, b);
}hello and hello
Cloning copies all the text, which takes a little time and memory, so Rust makes you ask for it explicitly. That way, expensive copies never happen by accident.
Small values are simply copied
Numbers, booleans and characters are small and live in a fixed amount of memory, so for them Rust just copies. Both variables keep working:
fn main() {
let x = 5;
let y = x;
println!("x = {}, y = {}", x, y);
}x = 5, y = 5
Functions take ownership too
Passing a String to a function moves it into the function, just like let b = a;. When the function ends, the value is dropped:
fn shout(text: String) {
println!("{}!", text.to_uppercase());
}
fn main() {
let word = String::from("rust");
shout(word);
println!("The word was given away.");
}RUST! The word was given away.
Using word after the call would be an error. Giving values away every time would be tiring, of course, which is exactly what the next topic, borrowing, solves.
Practice exercises
- Open the first example in the editor, read the error, and fix it in two different ways: with
clone, and by printing onlyb. - Show that an
i32can be used afterlet y = x;, but aStringcannot. - After
shout(word);, try to printwordand read the hint below the error.