Prep: Ownership — 02r¶
Session: Thursday Sep 3, 1 h 45 min · Exercises: 02r_ownership · Prep time: ~25 min · Lecture: Ownership, Borrowing, and Lifetimes
What you will build¶
A physical page allocator modeled by hand from a Vec<usize> of free page numbers and move semantics. There is no & yet, so each piece takes the whole free list by value and hands it back in a tuple: build the list at "boot," hand a page out like kalloc, take one back like kfree, and return a sentinel page number that can never be real when the list runs dry. One small piece shows that a String given to a function must be handed back before the caller can use it. The given tests check that no page is handed out twice, that a returned page becomes free again, and that page numbers survive being passed around while the list does not.
Concepts you need¶
- One owner; drop at the closing brace — Lecture §2 · Guide §1 "The rule"
- What a move is: three words copied, old name dead — Lecture §2.1 · Guide §1 "Moving"
- Moves across a call; returning a value to give it back — Lecture §2.2 · Guide "E0382"
Copytypes: page numbers copy, the list moves — Lecture §2.3 · Guide §1 "Copytypes"- Drop is where
free()went — Lecture §3 · Guide §1 "Drop" Vecbasics, tuples, shadowing — Lecture Problem 1 · Guide §5- Reading E0382 and the missing-
muterror — Lecture §7 · Guide "Common compiler errors"
Read before class¶
| What | Time |
|---|---|
Lecture §§1–3 (the bug, ownership, moves, Copy, drop) |
12 min |
| Lecture §7, the E0382 row and the reading habits | 3 min |
| Guide §1 Ownership and moves | 6 min |
| Guide §5, "Three ways to hold a run of values" | 3 min |
Mental model¶
A function that takes an owned value, changes it, and gives it back, plus a number riding along:
fn stamp(mut msg: String, n: u32) -> (String, u32) {
msg.push('!'); // legal only because the parameter says `mut`
(msg, n + 1) // hand the String back
}
let msg = String::from("boot");
let n = 7;
let (msg, total) = stamp(msg, n); // moved in, moved back out into a new `msg` (shadowing)
assert_eq!(n, 7); // `u32` is Copy: the original survives
assert_eq!((msg.as_str(), total), ("boot!", 8));
While stamp runs it is the only owner of that String. The kernel's allocator needs that: while "hand out a page" runs it owns the whole free list, so the page it returns cannot still be on it. Ownership is that invariant, checked by the compiler.
Check yourself¶
- After
let b = a;wherea: String, what happens at run time, and what at compile time?Answer
Run time: three machine words (pointer, length, capacity) are copied; the heap buffer is untouched. Compile time:ais marked dead; naming it again is E0382, a use-after-free caught early. - Which of these are
Copy:usize,bool,String,Vec<usize>,(usize, usize)?Answer
usize,bool, and the tuple; notStringorVec<usize>. The line is not size but resources: a type with cleanup (Drop) cannot beCopy, or cleanup would run once per copy. - A function takes a
Vec<usize>by value and calls.pushon it; the caller needs the list afterward. Without&, what must it do?Answer
Writemutbefore the parameter name (or.pushis E0596), and return theVec, usually in a tuple. The caller rebinds withlet (list, x) = f(list);, shadowing the deadlist.
What "done" looks like¶
oslings run is green, then oslings submit before you leave. Not green? Submit anyway (substantial credit), then finish by Thursday 11:59 pm and submit again.
If you finish early¶
Rustlings: 06_move_semantics, then 05_vecs and the tuple exercises in 04_primitive_types. 100 Exercises To Learn Rust: chapter 3, the Ownership, Stack, Heap, and Destructors sections; chapter 4, Copy and Drop. Then start Friday's prep page on borrowing, the fix for every "return it so the caller keeps it" line.