References: &, &mut, ref, * and the pointers beside them¶
Ownership › References
Level: 101 → 301 · a learning path
One line: A Rust reference is a pointer carrying promises the compiler checks — never null, never outliving what it points at, and never usable while a &mut to the same place is live. The lessons that teach it are spread over five sections of the library; this folder lists them in the order they build on each other, and adds the pages that were missing.
Pages marked new live in this folder. The rest are existing lessons elsewhere, linked in place rather than repeated. Go top to bottom, or find what surprised you in the next table and start there.
Find your page¶
| If this surprised you | Start at |
|---|---|
!flag compiles on a flag: &bool, but if flag does not |
When you need the * |
flag == true is refused, and n > 1 fails with a different error code |
When you need the * |
.filter(\|b\| **b) needs two stars |
When you need the * |
let &x = r; removes a reference, and the * in *const T dereferences nothing |
Where the & sits |
a borrow error's ^ points at the push, not at the later read that made it an error |
A borrow is a loan |
&mut v[1] borrowed the whole Vec |
A borrow is a loan |
an i32, which has no destructor, was "dropped here while still borrowed" |
A borrow is a loan |
while &b is held, the owner cannot assign to b or move it |
Borrowed state |
a &mut, which is not Copy, was passed to three calls in a row |
Reborrowing |
Some(_n) moved the value although _n is never used |
The ref keyword |
match &x { Some(ref n) => … } compiles on edition 2021 and is an error on 2024 |
The ref keyword |
| one pattern moved one field and borrowed another | The ref keyword |
*t = &mut t[1..] does not compile, and rustc's suggested &'a mut &'a mut breaks the caller |
Re-pointing a slice |
reading from a &[u8] moved the slice forward |
Re-pointing a slice |
<'a> did not make anything live longer |
Lifetime annotations |
after one call taking &'a mut Node<'a>, the node could never be printed, borrowed or moved again |
Borrowing something forever |
a struct holding a String and a &str into it compiles in main and not in fn new |
A struct that points into itself |
Box<str> is two words, and moving out of *boxed compiles where *rc does not |
Six pointer types, one table |
a table said &T lives on the stack and has shared ownership |
Six pointer types, one table |
Option<&T> is the same size as &T |
Six pointer types, one table |
a Cell changed behind a & |
Interior mutability |
a pointer made from p.addr() compared equal to p and reading through it was still undefined |
Address, pointer, reference |
a reference has to be aligned to the type it points at, not to usize |
A reference is aligned to its referent |
| a snippet from Stack Overflow, The Book or a course did not compile as printed | Reference claims, run |
let mut r = &a re-points r, let r = &mut a writes through it, and a book called &mut &T a fifth kind of reference |
Mutable binding, mutable reference |
The path¶
Before you start, the memory the rules protect: Stack and heap (where a value's bytes live), The call stack (what a call does to them) and A stack slot is reused (why a pointer into a finished frame is a bug and not a curiosity).
| # | Page | What clicks |
|---|---|---|
| 1 | Where the & sits decides what it does |
& and * do different jobs in a type, an expression and a pattern, so *r names a place |
| 2 | Borrowing | many readers or one writer, and a borrow ends at its last use |
| 3 | new A borrow is a loan | how the compiler decides: each reference records a loan, two conditions are checked, and every labelled line of a borrow error is one of them |
| 4 | Borrowed state | the same loan from the owner's side: E0505 and E0506 |
| 5 | Reborrowing | a call site passes &mut *r, so a &mut is not moved into the call |
| 6 | new Mutable binding, mutable reference | let mut against &mut: two choices, four combinations, nested forms such as &mut &T, and the shared reborrow &*z |
| 7 | new When you need the * |
the five places Rust writes the * for you, and why if flag is not one of them |
| 8 | new The ref keyword, then Match ergonomics |
a binding that borrows instead of moving — and the default binding mode that means you rarely write it |
| 9 | new Re-pointing a slice | &mut &mut [T]: a &mut to the caller's reference, mem::take, and Read for &[u8] |
| 10 | How to learn lifetimes → Lifetime annotations → What &'a T claims → Lifetimes at the call site → Temporary lifetime extension |
the loan's length written into a signature, and what it costs the caller |
| 11 | new Six pointer types, one table | &T, &mut T, *const T, *mut T, Box<T> and Rc<T> on seven questions, each cell run |
| 12 | The Pointers section: Address, pointer, reference → Wide pointers → Aligned to the referent → Raw pointers | what a pointer's value holds — a type, provenance, a second word, an alignment — and what goes when the promises do |
| 13 | Rc · Arc · Interior mutability · Cow |
several owners, writing through a &, and borrowing until somebody writes — and the Smart pointers section: Deref, Drop, and what each one allocates |
| 14 | What unsafe turns off · Use-after-free · Null dereference · Iterator invalidation · Lifetime safety in Clang |
raw pointers, and the C and C++ bugs the rules above make unwritable |
Beside the path:
- new What reference explanations get wrong, run — claims from a Stack Overflow thread, The Book, Programming Rust, Cliffle's Learn Rust the Dangerous Way and a chat answer, each checked on rustc 1.98.0.
- What Rust: The Practical Guide says about ownership in functions, run — a fourth book's chapter on ownership in functions, listing by listing: the move that copies no heap bytes, the
Copyrule behind "stack-only", and theE0106that is not a borrow error. - new Every reference error, and its fix — the compiler errors of this path by symptom: the code, rustc 1.98.0's words, the mistake and the fix, both halves checked on every build.
- new Lints around references — rustc and clippy warnings about borrows,
ref,*and raw pointers, bad and good, and what no lint catches. - new Helpful resources — chapters, docs, a paper, articles and videos for each part of the path, with the ones to read with care.
Katas along the path¶
The pages say what to understand; these make you write it. Each lives on its page, with a compiled solution folded under it.
| After step | Kata | On |
|---|---|---|
| 2 | Many readers, or one writer — two shared borrows, then a mutable one, and the println! that moves the end of a borrow |
Borrowing |
| 3 | Reference to a local variable — name the loan and the condition the } breaks, then fix E0597 two ways |
A borrow is a loan |
| 6 | Eight one-line edits — let or let mut, & or &mut: predict E0384, E0594, E0506 or a clean compile for each |
Mutable binding, mutable reference |
| 7 | Fewest stars — six lines without a * or &, each fixed with the fewest and the rule named |
When you need the * |
| 8 | Borrow one field, move the other — one let pattern, and why &upload cannot do its job |
The ref keyword |
| 8 | One character apart — Some(name) against &opt and against opt |
Match ergonomics |
| 9 | Split off the header — advance a &mut &[u8] and a &mut &mut [u8] |
Re-pointing a slice |
| 11 | Pick the pointer — a config reader, a tree's children, a shared cache and C's memchr |
Six pointer types, one table |
| 13 | Predict the count four times — one roster shared by three tallies, and the edge that leaks | Rc |
The full sequence, with every other kata in the library, is KATAS.md.
Four symbols, four different kinds of thing¶
The most-voted Stack Overflow answer on this question opens by separating them, and the separation is the first thing to hold on to:
| You see | What it is | Where it is taught |
|---|---|---|
&x, &mut x · &T, &mut T |
an operator that borrows, and the sigil of a reference type | Where the & sits, Borrowing |
*r · *const T, *mut T |
an operator that dereferences, and the sigil of a raw pointer type, where it dereferences nothing | When you need the *, Where the & sits |
ref x, ref mut x |
pattern syntax: bind by reference instead of by move | The ref keyword |
Box<T>, Rc<T> |
library types that own what they point at | Six pointer types, one table |
Tests for anything else you read¶
Most explanations of references state the rule correctly and get one fact under it wrong. The tell for each:
- "
refis the same as&." In a pattern they are opposites:ref xmatches the same values asxand binds a reference, while&xmatches only a reference and binds what is behind it — Therefkeyword. - "The compiler flags the line where you use the old reference." The
^is under the use of the owner that breaks the loan; the later read is the line labelled later used here — A borrow is a loan. - "At run time a reference is just an address." For
&u32. A&stror&[T]is an address and a length — claim 3. - "References live on the stack." A reference is a value like any other: in a
Vec<&str>the references are on the heap, and the pointee can be anywhere — Six pointer types, one table. - "
Box<T>is always one pointer wide." Not whenTis unsized:Box<str>andBox<dyn Trait>are two words — Six pointer types, one table. - "
*const Tand*mut Tdiffer only as a lint." They cast freely, but they differ in variance — Six pointer types, one table. - "
Rc<T>is read-only." ThroughDeref.Rc::get_mutwrites while the count is one — claim 5. - "Rust auto-derefs, so
if flagshould work on a&bool." Auto-deref happens at the dot and in coercions between reference types, never into a condition — When you need the*. - "An unused binding such as
Some(_n)does not move anything." It moves; only_binds nothing — Therefkeyword. - "Apply rustc's
help:and it compiles." It does — and on&mut &mut [T]the suggested'aon both layers makes the caller the next error — Re-pointing a slice.
If you are coming from another language¶
- C has no references, only pointers —
int &r = x;does not parse as C (the clang run). Every C pointer parameter leaves the same four questions to the caller: may it be null, how many elements does it cover, is the memory initialized, and who else is writing through it. A Rust reference answers all four in its type, which is Cliffle's argument in Learn Rust the Dangerous Way part 2 and the subject of Six pointer types, one table. The C library runs the length question twice: A string is bytes up to a NUL ↗, where an array forgets its length the moment it is passed to a function, and The functions that do not check ↗, wherestrcpywrites past a destination whose size it was never told. - C++ has
T&, and it is the closer neighbour — a reference that cannot be null — but the similarity ends at the lifetime. Apple clang 21 builds anint&returned to a local with a warning, and anint&into astd::vectorheld acrosspush_backwith none, even under-Wall -Wextra(the run). Rust refuses both, and A borrow is a loan names the condition each one breaks. The heap version of the same bug is run in Use-after-free. - Python gives every name a reference and checks nothing: two names can alias one dict, and growing it while a loop walks it raises
RuntimeErrorat run time. Rust makes aliasing and mutation mutually exclusive before the program runs — Borrowing names the Python error for the same bug. The Python library'sbytearrayis the mutable one ↗ makes the matching point from the other side: an immutablebytescan be handed to a function with no defensive copy because nobody can change it, which is what a&Tpromises for every type.
See also¶
- How to learn lifetimes — the same kind of page, for the other wall
- Borrowing something forever and A struct that points into itself — two lifetime traps checked against quinedot's guide, with their own errors, lints and reading pages
- Pointers and Smart pointers — the two sections on what a pointer holds and what a smart one manages, checked against Rust in Action ch. 6
- How to learn
ToOwned— where references meetClone, method lookup and unsized types - Ownership — the section this folder sits in
- Glossary — shared reference, exclusive reference, dangling reference, fat pointer, NLL
- Interior mutability ↗ in the Concurrency library's concept map — the same
Cell/RefCellexception, andMutexand atomics as its threaded form
Po polsku¶
Referencja w Ruście to wskaźnik z obietnicami, które sprawdza kompilator: nigdy nie jest pusta (null), nigdy nie przeżyje wartości, na którą wskazuje, i nie da się jej użyć, dopóki żyje &mut do tego samego miejsca. Lekcje o referencjach są rozrzucone po pięciu działach biblioteki; ten folder układa je w kolejności, w której jedna buduje na drugiej, i dodaje brakujące strony: model pożyczki (loan) z artykułu Stacked Borrows, kiedy trzeba pisać * (w tym &bool w if), słowo kluczowe ref, &mut &mut [T], tabelę sześciu rodzajów wskaźników oraz stronę z twierdzeniami z internetu i książek sprawdzonymi na rustc 1.98.0.
Cztery symbole to cztery różne rzeczy: & pożycza (i oznacza typ referencji), * dereferencjonuje (i oznacza typ surowego wskaźnika), ref to składnia wzorca, a Box i Rc to typy z biblioteki, które są właścicielami tego, na co wskazują.
Szukaj po polsku: referencja współdzielona · referencja mutowalna · pożyczanie · dereferencja · surowy wskaźnik · rust ref keyword · rust reference vs pointer