Skip to content

Ownership

One line: Every value has exactly one owner, moving it transfers responsibility rather than bytes, and a borrow lets somebody read it without taking that responsibility on — which together are what let Rust free memory with no garbage collector and no free() you can get wrong.

Three rules do the work, and the pages here try to make them visible rather than merely stated: a value that announces its own death shows exactly when a move happens, and &x printed before and after shows what actually changed (the three-word header, not the bytes).

Three pages in the middle are the mechanism the rest of the section polices: what a call does to memory, what happens when the calls stack up, and what happens to a frame after it returns — which is that it is handed to the next call, bytes and all. Everything the borrow checker refuses is a way of stopping you holding a pointer into one of those.

The back half is names rather than values. Shadowing, scope, and lifetimes are three different questions that English collapses into one word — a name ends at its brace, a borrow ends at its last use, and a value drops on a schedule five ordinary things can move — so the section separates them and then puts shadowing back through the borrow checker to prove the difference.

Lesson Level What it teaches
Ownership and moves 101 A move transfers responsibility, not bytes — the three rules, made visible by a value that announces its own death
Copy or move? 101 One program with the value swapped: "hi" copies because it is a &str, String::from("hi") moves, and &mut moves although it owns nothing — the column printed by asking the compiler, not a list
There is no Move trait 201 Moving is the default, so there is no trait to implement — Copy is the opt-out that stops it, and the compiler says so as an absence: "does not implement the Copy trait"
What an address shows 201 &x addresses the three-word header, not the text — so a move changes the number without relocating a byte, and a Copy does the same thing while nothing moves at all
Stack and heap 101 → 201 No keyword puts a value on the heap — the type does, and size_of shows it: a String is 24 bytes on the stack whether it holds 5 characters or 5,000. One table prices move, Copy, clone and Arc::clone against the heap side
The call stack 101 → 201 What a call does to memory: a region reserved, the arguments moved into it, the whole thing released on return — plus the footnote everyone skips, run rather than asserted (at -O the four frames are not there)
Recursion and the size of the stack 201 Depth is the cost, the bound is fixed when the thread is spawned, and running out is an abort: no unwinding, no Drop, and catch_unwind catches nothing
A stack slot is reused 201 A released frame is reissued, not cleared — the same address, a different value — which is the concrete reason for every rule on the next four pages. E0515 in Rust, a warning you can build past in C
Where the & sits decides what it does 101 → 201 The same two characters do three different jobs — &S is a type, &a is an operator, and &x in a pattern removes a reference rather than making one — so *r names a place rather than a value, and the * in *const S dereferences nothing at all
Borrowing 101 → 201 &T and &mut T, the many-readers-or-one-writer rule, and the last-use rule that decides which order compiles
Borrowed state 201 The same rule from the owner's side: &b locks b, so the two errors that follow (E0505, E0506) are not about a second reference at all — the owner is refused its own binding
Reborrowing 201 Why &mut acts like Copy when you pass it and moves when you bind it — a call site inserts &mut *r, a bare let does not, and adding a type annotation to that same let puts it back
How to learn lifetimes 201 Is "clone everything" good advice? Mostly yes — with three amendments, the sharpest being that cloning to dodge a mutation error compiles and silently does nothing
Lifetime annotations 201 <'a> names a relationship rather than granting a duration — E0106 and what its help line is asking, the three elision rules that make most signatures need nothing, and why a second lifetime permits more programs than reusing one
What &'a T claims 201 → 301 Three promises in one type, and the third is the one that decides what may be assigned into a reference — plus the single direction the compiler substitutes lifetimes for free, and where that reverses
What a lifetime does at the call site 201 → 301 Two functions with identical bodies, one of which releases an argument the other keeps locked — because the compiler reads the signature and never looks at the body
A name is not a place 201 What separates a shadow from mut, proved with the borrow checker rather than with addresses: the shadow compiles and the mut spelling is E0506, because one is a declaration and the other is a write
A shadow does not drop 201 What shadowing does to the value underneath: nothing — it is still alive, still borrowable, and it drops after the shadow that hid it, with no name left to release it early
When to shadow 201 The judgement call the other two leave open: what shadowing buys that mut cannot, the five idioms worth copying, and the three bugs that compile — only one of which warns, and not about shadowing
Nothing checks a shadow 201 The tooling, not the mechanism: rustc has no shadowing lint, the type error that gets mistaken for one, and the single clippy lint that catches the accumulator bug — by also banning the idiom
Scope is about names, not values 201 One word, three questions: a name ends at its brace, a borrow ends at its last use, and a value dies on a schedule that five ordinary things can move — including the _ that rustc denies outright on a lock
Assignment drops the old value 201 x = value frees what x was holding, so a value can die mid-function on a line with no brace — plus the two assignments that drop nothing, and the three std::mem functions that hand the old value back instead
Temporary lifetime extension 301 A temporary dies at the semicolon unless the let has one of a short list of shapes — so Holder { r: &make() } compiles and hold(&make()) is E0716, and a match holds its scrutinee through every arm
The drop flag 301 What the compiler does when it cannot tell from the source whether a location is still full: a hidden boolean in your stack frame, checked at the brace — and the reason E0509 refuses to split a Drop type
Cow: borrow until somebody writes 201 Borrowed or owned, decided at run time by the data — to_mut() is the write that pays for the clone, and the tag costs nothing: Cow<str> is the same 24 bytes as String
Rc: the clone that copies a pointer 201 Several owners for one value, counted — Rc::clone duplicates a pointer and a number, never the data, which makes it the cheapest .clone() in Rust and the most commonly misread one
Sharing across threads: Arc 201 The same counter made atomic — the difference is not a performance note but the reason one of the two compiles across a thread boundary, and Arc<Mutex<T>> is what shared mutable state costs
What a clone costs 201 A derived Clone clones every field, so it costs what the fields cost — two allocations for two Strings, none for two Arc<str>s, none for a move — and nothing at the call site says which

Cow, Rc and Arc are the ways out of a copy the one-owner rule would otherwise force: borrow until somebody writes, or let several owners share one value and count them.

  • Strings — the worked example most of these pages already use
  • StructsCopy vs Clone, which decides what = means
  • ToOwnedClone generalized to borrowed data
  • &'static str — the longest lifetime, filed with the strings because that is where you meet it: the E0597 that only bites off a non-literal, and why T: 'static the bound does not mean "lives forever"

  • Interior mutability — the one way to write through a &T, and what moving the borrow check to run time costs

SHADOWING.md is the full reading order for the names half.

Po polsku

To jest ten dział, w którym Rust przestaje przypominać inne języki, i zarazem jedyny, dla którego istnieje porządny polski materiał: Tour of Rust ↗ ma przetłumaczony cały rozdział 5, „Koncepcje Własności i Pożyczania Danych”. Warto go przejść równolegle — ta biblioteka trzyma się jego terminologii.

Słownik, na którym opiera się reszta działu:

English Polski
ownership własność (posiadanie danych)
owner właściciel
move przeniesienie własności
borrow, borrowing pożyczanie
reference referencja
mutable reference referencja mutowalna
scope zasięg
drop wypuszczenie zasobu
lifetime czas życia
shadowing przesłanianie
stack / heap stos / sterta
borrow checker borrow checker (nie tłumaczymy)

Trzy reguły własności, w formie do zapamiętania: każda wartość ma dokładnie jednego właściciela; właściciel jest tylko jeden naraz; gdy właściciel wychodzi z zasięgu, wartość zostaje wypuszczona. Reguła pożyczania jest jedna: wielu czytających albo jeden piszący, nigdy jedno i drugie naraz.

Dwa ostrzeżenia dla czytającego po polsku. Po pierwsze, „przeniesienie” nie oznacza, że dane wędrują w pamięci — przenosi się odpowiedzialność za zwolnienie, a bajty zostają na miejscu. Po drugie, sporo polskich materiałów opisuje jeszcze stan sprzed 2018 roku, w którym pożyczenie trwało do końca bloku. Od czasu NLL (non-lexical lifetimes) kończy się przy ostatnim użyciu referencji, i to zmienia odpowiedź na pytanie „dlaczego to się nie kompiluje” w bardzo wielu przykładach.

Druga połowa działu dotyczy nazw, nie wartości — przesłanianie, zasięg i czasy życia to trzy różne pytania, które polszczyzna (podobnie jak angielski) skleja w jedno „wychodzi z zasięgu”. Strona Zasięg dotyczy nazw rozdziela je na trzy.

Szukaj po polsku: własność i pożyczanie w Ruscie · przenoszenie własności · kontroler pożyczeń · czasy życia · rust ownership borrowing · rust NLL