01 Scalar types: what a value is in memory.
a value is its bits; usize is an address · point at the PTE decoded from a u64
Every program in examples/src/bin/ beside the output it printed, and every
file in examples/broken/ beside what rustc said about it. Each colored,
numbered section of code sits in the same row as the output it produced. Click an output line to light
up the println! that printed it, or click a println! to find its output.
Click a section's number to copy a link straight to that section, to paste where students will
follow it. Press i on a program to edit it and run it. On a phone the two columns do not fit, so a
Code/Output switch shows one at a time.
| Program | The one idea | The line to point at | Sections | |
|---|---|---|---|---|
| 01 | scalars | a value is its bits; usize is an address | the PTE decoded from a u64 | 6 |
| 02 | compound | structs/arrays/enums are plain layouts | size_of::<Option<&u8>>() == 8 | 5 |
| 03 | stack_and_heap | the handle is not the buffer | push printing a new buffer address | 6 |
| 04 | move | a move copies 3 words, not the data | 8 MiB "moved" with the same pointer | 5 |
| 05 | copy_types | Copy XOR Drop | two independent Pte copies at different addresses | 6 |
| 06 | drop | free() became a scope | kfree lines in reverse declaration order | 6 |
| 07 | borrow_shared | many readers, no ownership | three references printing one buffer address | 5 |
| 08 | borrow_mut | &mut means exclusive | split_at_mut — two writers, provably disjoint | 6 |
| 09 | slices | ptr + len, checked | one checksum over an array, a Vec, and a slice | 6 |
| 10 | how_to_pass | choosing T / &T / &mut T | the mini PageAlloc with &self and &mut self | 2 |
| Error | What rustc says | The fix |
|---|---|---|
| E0106 | missing lifetime specifier (and, once you add one, error[E0515]: cannot return reference to local) | return the value, or borrow from a parameter |
| E0382 | borrow of moved value | use t, clone(), or borrow |
| E0499 | cannot borrow v as mutable more than once at a time | sequence them, or split_at_mut |
| E0502 | cannot borrow v as mutable because it is also borrowed as immutable | finish the read first; or copy the value out |
| E0505 | cannot move out of s because it is borrowed | use the reference before the move |
| E0507 | cannot move out of index of Vec<String> | borrow, clone(), or remove() |
| E0596 | cannot borrow v as mutable, as it is not declared as mutable | add mut |
| Space j ↓ → | next section (dims the rest) |
| Shift+Space k ↑ ← | previous section |
| 0–9 | jump to that section |
| click | pin an output line and the code that printed it (click again to unpin) |
| click a number | copy a link to that section, or to the whole example from the number beside its title |
| l | copy a link to the pinned line, else the section in focus, else this example |
| Esc | unpin, then leave section focus, and drop it from the link so a reload does not bring it back |
| n p | next or previous example |
| r | next run, for programs run more than once |
| e | open or close the explanation (broken files) or the build warnings |
| + - | larger or smaller text (remembered) |
| i | edit this program and run it |
| ⌘/Ctrl+↵ | run what you have edited |
| c | compare: what you changed in the code, and what changed in the output (press Esc first if you are typing) |
| o | on a narrow screen, switch between the code and the output column |
a value is its bits; usize is an address · point at the PTE decoded from a u64
structs/arrays/enums are plain layouts · point at size_of::<Option<&u8>>() == 8
the handle is not the buffer · point at push printing a new buffer address
a move copies 3 words, not the data · point at 8 MiB "moved" with the same pointer
Copy XOR Drop · point at two independent Pte copies at different addresses
free() became a scope · point at kfree lines in reverse declaration order
&T. Lend it, don't give it away.many readers, no ownership · point at three references printing one buffer address
&mut T. Read it as exclusive, not "mutable".&mut means exclusive · point at split_at_mut — two writers, provably disjoint
ptr + len, checked · point at one checksum over an array, a Vec, and a slice
choosing T / &T / &mut T · point at the mini PageAlloc with &self and &mut self
missing lifetime · fix: return the value, or borrow from a parameter
This is C's returning-a-pointer-to-a-stack-local. Rust asks the question that exposes it: borrowed from WHAT? There is no input to borrow from, and s dies at the closing brace.
use of moved value · fix: use t, clone(), or borrow
The use-after-free, caught at compile time. s gave the buffer away on the let t = s; line, so the name s is struck off from there on.
t instead.let t = s.clone(); — pay for a second buffer, visibly.let t = &s; — borrow instead of taking.v as mutable more than once at a timetwo &mut at once · fix: sequence them, or split_at_mut
&mut means EXCLUSIVE. Two writers to the same value at the same time is the data race, and it is rejected even in single-threaded code.
split_at_mut.v as mutable because it is also borrowed as immutable& and &mut overlap · fix: finish the read first; or copy the value out
ALIASING XOR MUTATION. first points into the Vec's buffer; push may reallocate that buffer and free the old one. In C++ this compiles and first becomes a dangling pointer.
first before pushing (borrows end at their last use).let first = v[0]; (i32 is Copy).s because it is borrowedmove while borrowed · fix: use the reference before the move
A borrow is a claim on the value staying put. You cannot hand the value to someone else while a reference to it is still alive.
r before the move, or borrow again after it.Vec<String>move out of a Vec index · fix: borrow, clone(), or remove()
If this were allowed, the Vec would still believe it owns element 0 and would free it at the end of the scope — while first also freed it. A double free.
v as mutable, as it is not declared as mutablenot declared mutable · fix: add mut
Immutability is the default, and it is a real guarantee, not a style rule.
let mut v = ...