Skip to content

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:

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:

  • "ref is the same as &." In a pattern they are opposites: ref x matches the same values as x and binds a reference, while &x matches only a reference and binds what is behind it — The ref keyword.
  • "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 &str or &[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 when T is unsized: Box<str> and Box<dyn Trait> are two words — Six pointer types, one table.
  • "*const T and *mut T differ only as a lint." They cast freely, but they differ in variance — Six pointer types, one table.
  • "Rc<T> is read-only." Through Deref. Rc::get_mut writes while the count is one — claim 5.
  • "Rust auto-derefs, so if flag should 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 — The ref keyword.
  • "Apply rustc's help: and it compiles." It does — and on &mut &mut [T] the suggested 'a on 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 ↗, where strcpy writes 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 an int& returned to a local with a warning, and an int& into a std::vector held across push_back with 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 RuntimeError at 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's bytearray is the mutable one ↗ makes the matching point from the other side: an immutable bytes can be handed to a function with no defensive copy because nobody can change it, which is what a &T promises for every type.

See also

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