Vibe Engines
YouTube

Lesson 4.1 · 8 min

One owner, one key

Every piece of data in a Rust program has exactly one owner, like a room with a single key. This one idea is what Rust is famous for, and once you can picture it the rest of the chapter is easy.

Adds to ChatterboxThe mental model; no code change.

The one-key rule

Chatterbox now holds messages as text it can change and pass around. Before we let it do more, we need one idea, because Rust is strict about it and everything else in this chapter hangs off it.

Picture each piece of data as a room, and each room has exactly one key. Whoever holds the key owns the room. That is the whole model:

  1. Every value has exactly one owner. The owner is a variable.
  2. When the owner goes away, the value is cleaned up. The key is thrown out and the room is emptied.

Two more things can happen to a key, and they get a lesson each. As a preview: you can hand it over or lend it out. Nothing else. Those are the two moves you will use most; cloning comes in the next lesson.

Watch a key appear and go

Here is a small program with two variables, one inside a pair of braces. The braces make a scope: a stretch of code where a name exists. Step through it. The left side is the code, the right side is memory. A solid arrow means owns.

Ownership StageA variable owns its text until its scope ends

Step through the program. Solid arrows are ownership; dashed arrows are borrows. Use ← → or the slider.

fn main() {
let msg = String::from("hi chatterbox");
{
let note = String::from("scratch");
println!("{note}");
}
println!("{msg}");
}
  1. Line 1. The program starts in main. Its variables will live in this frame.
  2. Line 2. A String is made. Its text lives in a block of memory called the heap, and the variable msg owns it: msg holds the key.
  3. Line 4. Inside the braces a second String is made. note is its one owner.
  4. Line 5. note is used while it still exists. This prints scratch. stdout: scratch
  5. Line 6. The closing brace ends the scope. note goes away, so its text is cleaned up right here. You wrote no code for that; Rust put it in.
  6. Line 7. msg is still in scope, so it still owns its text and can use it. This prints hi chatterbox. stdout: hi chatterbox
  7. Line 8. main ends, so msg goes away and its text is cleaned up too. Everything that was made has been cleaned up, exactly once.

That cleanup at the closing brace is why you never write "free this memory" in Rust and also never leave a leak. The place where each value is cleaned up is not a guess. It is the line where its one owner goes out of scope.

Try the next one before you read the answer. The program uses a name outside the braces where it was made.

PredictUsing a value after its owner is gone
fn main() {
{
let note = String::from("scratch");
}
println!("{note}");
}

Does this compile — and if it does, does it run?

  • It compiles and runs
  • Compile error E0425
  • Compile error E0382
Reveal the answer

It does not compile: E0425. The braces end the scope, so the name note does not exist on the next line. The compiler says it cannot find the value. The owner is gone, and so is the room.

error[E0425]: cannot find value `note` in this scope
 --> src/main.rs:5:16
  |
5 |     println!("{note}");
  |                ^^^^
  |
help: the binding `note` is available in a different scope in the same function
 --> src/main.rs:3:13
  |
3 |         let note = String::from("scratch");
  |             ^^^^

Why one key?

A program that frees memory twice, or uses it after it was freed, crashes or opens a security hole. Those bugs happen when two parts of a program both think they are in charge of the same data. The one-key rule makes that impossible: only one owner, so only one cleanup, and a name whose key is gone cannot be used.

Python avoids the same bugs a different way: it keeps a count of how many names point at each value and cleans up when the count hits zero. That is a fine design. Rust does the bookkeeping while compiling instead, so the finished program has no counting to do.

Keys can leave through a return

A function can make a value and give its key to whoever called it. The value is the function's result. Nothing is cleaned up, because the owner changed instead of going away. Your turn: write a function that builds a labelled message and returns it.

Try itYour turn: build a message and hand it back

Make label return you: followed by the message, as a new String. The caller becomes its owner.

Make label return you: followed by the message, as a new String. The caller becomes its owner.

fn label(msg: &str) -> String {
// build: you: <msg>
String::new()
}
 
fn main() {
let line = label("hello");
println!("{line}");
}

Hidden tests (3): keeps_the_text_whole labels_a_message empty_message_still_gets_a_label

This exercise runs real Rust in your browser through the official Rust Playground, so it needs JavaScript.

What you have now

Chatterbox has no new code in this lesson. What you have is the rule that decides how every later line is written: one value, one owner, cleaned up when the owner goes. Next, what happens when you want to give the key to somebody else.

Self-check

Say it out loud, then reveal

Self-checkRetrieval beats re-reading
State the one-key rule in a sentence.Reveal
Every value has exactly one owner. When that owner goes out of scope, the value is cleaned up.
Where exactly is a variable's text cleaned up?Reveal
At the closing brace of the scope where the variable was made, the moment its owner goes out of scope.
How can a function give a new value to its caller?Reveal
By returning it. The key moves to the caller, so nothing is cleaned up.

That is lesson 4.1. Tick it off so the course remembers where you are.

Learn Rust by building a chat app · Lesson 4.1 · every compiler message above is real output from rustc 1.99.0 (b940084d7 2026-09-28) (edition 2024) · Vibe Engines · 2026