Advanced¶
Pages that assume the Foundations spine and then add a second hard thing on top — shared state across threads, unsafe, FFI, macros, layout and performance. Nothing here is harder to read than a Foundations page; what makes it advanced is that the mistakes cost more and the compiler helps less.
Each page is still one idea with a program you can compile and run beside it.
| Lesson | Level | What it teaches |
|---|---|---|
| Spawning a thread | 201 → 301 | spawn, the JoinHandle that is the only way to a return value, the 'static bound behind E0373, and thread::scope — which borrows what spawn cannot, so a fan-out needs no Arc at all |
| Channels | 201 → 301 | Handing a value over instead of sharing one: send moves, the Sender you kept that stops the program exiting, the difference between empty and disconnected, and when a bound is backpressure rather than a limit |
| Lock poisoning | 301 | Why Mutex::lock() returns a Result at all, what your .unwrap() is deciding on someone's behalf, and the three honest answers |
| The right to post is a value | 301 | Authentication as a type rather than a boolean — a permission that cannot be forged, a post that spends it, and the hole move semantics still cannot close |
| Scale the denominator away | 301 | Exact arithmetic without fractions — why a float breaks a tied count, why the rationals that fix it cost a gcd apiece, and when you can multiply the denominators out and spend the count in i128 |
What i128 is exact about |
301 | The three different properties "exact" gets used for, which one a 128-bit integer actually has, what widening costs per operation — and why fractions.Fraction is a different trade rather than a slower one |
| When the denominators compound | 301 | The proportional allocation the companion trick cannot reach — why its denominators compound out of the previous round's, why the width you need is a property of the data, and what a fixed-width rational really runs out of |
| Did the rounding decide it? | 301 | The question the other four do not ask — bracket each rounded term instead of storing it, and find out whether your choice of scale or the data picked the answer; sound but not complete, so decided is a proof and undecided is only about that scale |
| What an invariant is | 301 | The promise a type carries — established at the one door that can build it and assumed everywhere else, which is why .chars() validates nothing and has no error case to handle; the two clauses of Chars::next's SAFETY comment and why the second follows from the first; and the ordinary kind, where breaking one costs a wrong answer rather than undefined behaviour |
What unsafe turns off |
301 | The five powers it grants and the nothing else it turns off — the borrow checker still runs inside the block; split_at_mut as a safe API over a small unsafe core; unsafe fn vs unsafe {} after edition 2024; and why the audit unit is the module, because a safe line three away is what makes the block sound |
| Calling C | 301 | "No overhead FFI" is a claim about the call — extern "C" is an ordinary call instruction with no marshalling layer. The data is the bill: a &str carries a length and a C string carries a terminator, so every string that crosses is allocated and copied, and the conversion can fail. Plus edition 2024's unsafe extern and its safe fn, and the unbounded lifetime CStr::from_ptr hands back |
| What a union is | 301 | Fields on top of each other instead of side by side — why the write is safe and the read is not, why the field type decides whether a bad read is merely wrong or undefined, and why an enum is this with the tag already checked |
| Interior mutability | 301 | Writing through a &T — Cell and RefCell move the borrow check from compile time to run time, which buys the shapes the static checker cannot prove and costs a panic instead of an error. Stub |
Send and Sync |
301 | The two methodless traits that decide what may cross a thread boundary, why nobody writes either, and why the error always names a type three layers inside the closure. Stub |
RwLock and atomics |
301 | The two rungs either side of a Mutex — and the reason two atomics read together are not atomic together. Stub |
| The global allocator | 301 | Where every heap byte comes from — swapping in a counter that turns String's capacity ladder into events you can see, the three rules that keep such a measurement honest, and why the five ways to make a String all cost exactly one allocation |
Allocator::shrink |
301 | The request Vec::shrink_to_fit bottoms out in — the three-way branch behind "may either shrink in-place or reallocate", why shrinking to zero is not a shrink, why the old pointer is dead even when the block never moved, and the provided body that turns giving memory back into the most expensive operation available |
Planned¶
Rough order, not a promise. The three that used to sit here — Send/Sync, RwLock and atomics, and interior mutability — are stubs in the table above now, which is the same list with their boundaries written down. FFI has since left this list for the table: Calling C.
- Macros —
macro_rules!and the procedural kind, once what the!means has been said at 101
Po polsku¶
„Zaawansowany” brzmi po polsku jak zapowiedź trudniejszej składni, i akurat tutaj znaczy coś innego. Żadna z tych stron nie jest trudniejsza w czytaniu niż strony z 01_Foundations — zaawansowane jest to, że błąd kosztuje więcej, a kompilator pomaga mniej. W unsafe nie znika borrow checker (działa dalej, w środku bloku), znika tylko kilka konkretnych gwarancji; przy FFI i przy surowych wskaźnikach to ty bierzesz na siebie dowód, którego dotąd wymagał od ciebie kompilator. Wątki są w tym rozdziale z tego samego powodu: spawn wymusza 'static, thread::scope pozwala pożyczyć zamiast klonować, a Mutex::lock() zwraca Result nie bez przyczyny — twoje .unwrap() podejmuje wtedy decyzję za kogoś innego.
Rozdział ma jeden garb, którego nie znajdziesz w typowym „advanced Rust”: cztery strony pod rząd o dokładności liczenia — skalowanie mianowników, co właściwie jest dokładne w i128, co się dzieje, gdy mianowniki narastają z rundy na rundę, i arytmetyka przedziałowa, która jako jedyna pyta, czy o wyniku nie zdecydowało zaokrąglenie. To nie jest teoria liczb dla ozdoby: liczenie głosów na f64 potrafi rozstrzygnąć remis w złą stronę, a „dokładny” to po polsku, tak samo jak po angielsku, słowo używane na trzy różne sposoby naraz.
Praktyczna uwaga do czytania tabeli: pozycje oznaczone Stub to celowo zapisane granice tematu, a nie gotowe lekcje — po polsku najbliższe będzie „szkic”. I nie szukaj polskich odpowiedników nazw z tej tabeli: Send, Sync, unsafe, union i cała reszta to słowa kluczowe albo nazwy typów, więc odmieniamy je po polsku („w unsafe”, „przez Mutexa”), ale nie tłumaczymy.
Szukaj po polsku: wielowątkowość w Ruscie · arytmetyka dokładna zamiast zmiennoprzecinkowej · rust unsafe what it turns off · rust thread scope borrow · rust mutex poisoning