Shiklo Tools
PDF40
Image20
Calculators & Converters25
Text & Writing13
Developer26
Video14
Audio14
Document14
Data & Spreadsheet12
Web & SEO9
OCR & Scanning5
Archive & File12
Security & Privacy23
Health & Medical29
QR & Barcode5

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

  1. Every value has one owner, a variable that is responsible for it.
  2. There is only one owner at a time.
  3. 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);
}
The compiler says
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);
}
Output
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);
}
Output
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.");
}
Output
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

  1. Open the first example in the editor, read the error, and fix it in two different ways: with clone, and by printing only b.
  2. Show that an i32 can be used after let y = x;, but a String cannot.
  3. After shout(word);, try to print word and read the hint below the error.