Skip to content

1.6 Ownership and borrowing: aligning with Rust's core terms

Across the first five sections, without writing a single line of real Rust syntax, we followed physical stack-and-heap constraints step by step to build an automatic memory reclamation model that needs neither manual free calls nor a runtime garbage collector.

In this final section of Chapter 1, we bring out the standard terminology from the official Rust documentation and match each term directly to the mechanisms you just derived.

First, look at the three ownership rules from The Book

Section titled “First, look at the three ownership rules from The Book”

Open Chapter 4 of the official Rust tutorial (The Book), and the very first rules you meet are the famous Ownership Rules:

  1. Each value in Rust has an owner.
  2. There can only be one owner at a time.
  3. When the owner goes out of scope, the value will be dropped.

If you try to memorize those three lines cold, they can feel like arbitrary dogma. Match them against what we derived in Section 3, however, and every line maps to a concrete physical requirement:

  • Rules 1 and 3 (who frees memory, and when): a heap resource has no built-in exit moment of its own, whereas the stack variable controlling it has a deterministic scope exit (}). Naming that stack variable the owner and having it automatically drop (free) the resource on leaving {} eliminates manual free calls.
  • Rule 2 (why only one owner at a time): if an assignment t = s left both variables pointing at the same heap block, leaving {} would free that block twice (a double free). To guarantee each heap block is freed only once, assignment must invalidate the old variable on the spot and transfer cleanup responsibility to the new one—a Move; by contrast, stack-only values like integers carry no heap cleanup duty, so a bitwise copy leaves both variables valid—a Copy.

Next, match “borrowing” and “lifetimes”

Section titled “Next, match “borrowing” and “lifetimes””

With the three ownership rules alone, even a read-only call print_it(s) moves and invalidates the caller’s variable. To close that gap, Section 4 and Section 5 introduced two more mechanisms:

  • References (&T) and borrowing: a type that holds only an 8-byte stack address and is stripped of cleanup duty is called a reference; handing that address to other code without giving up ownership is called borrowing (“you get the address to use the data; the duty to free it stays with me”).
  • Lifetimes and the borrow checker: because a reference does not manage cleanup, it would dangle if the original variable exited scope and freed the heap first. The compiler pass that checks at compile time whether moved variables are used again and whether a reference’s valid span (lifetime) stays within its owner’s live span is called the borrow checker.

Placed side by side, the mechanisms from our five sections map onto Rust’s vocabulary in one compact table:

Mechanism you derived Official Rust term One-sentence takeaway
The single variable responsible for freeing a heap resource on leaving {} Owner / Ownership Whoever owns the value is responsible for freeing it at scope exit
The cleanup action triggered automatically when a variable leaves {} Drop The cleanup call the compiler inserts for you at {}
Keeping both variables valid vs. invalidating the old variable on = Copy / Move No cleanup duty means Copy; transferring cleanup duty means Move
An address-only &T stripped of cleanup duty, and passing that address around Reference / Borrowing You get the address to use the data; cleanup duty stays with the owner
Comparing a reference’s use span against its owner’s live span at compile time Lifetime / Borrow Checker Guarantees a reference never outlives the data it points to

At bottom, it is all about safely inserting that one free call

Section titled “At bottom, it is all about safely inserting that one free call”

When people first encounter the string of terms “ownership, move, borrowing, lifetimes,” it is easy to assume Rust runs a complex management engine under the hood.

Strip away the vocabulary, and the entire system exists to do one remarkably plain job: let the compiler figure out at compile time the exact closing brace } where it can safely insert a free call (called drop in Rust) on your behalf.

Look at how the pieces line up:

  1. Ownership and Drop tell the compiler which {} should receive the free call, ensuring no allocation is ever forgotten (preventing memory leaks).
  2. Move semantics (single owner) ensure that each heap allocation has free inserted for it only once, never twice (preventing double frees).
  3. Borrowing and lifetimes ensure that after that inserted free call runs, no reference anywhere can read that memory again (preventing dangling references).

Once the borrow checker verifies those three guarantees at compile time and places the cleanup instructions at the right closing braces, ownership, borrowing, and lifetimes are completely erased from the generated machine code. At runtime, there is no garbage collector scanning memory and no reference count ticking up and down—only direct allocations and deallocations, just like hand-written C.


Next step: open the compiler and read real Rust code

Section titled “Next step: open the compiler and read real Rust code”

With the baseline model in place, real-world programs will naturally raise further questions—such as how to mutate data through a reference without interference (Part 2 introduces mutable references &mut T) and how multiple components can share ownership at runtime (Part 3 introduces reference counting Rc).

Before stepping into those topics, Chapter 2 opens the compiler and puts this baseline model to work in everyday Rust code: writing let and = to see firsthand how the compiler applies these rules across declarations, reassignment, and shadowing.

Next chapter: Variables and assignment →