Prep: Borrowing and Lifetimes — 03r¶
Session: Fri Sep 4, 1h30 · Exercises: 03r_borrowing · Prep time: ~30 min · Lecture: Ownership, Borrowing, and Lifetimes
What you will build¶
Thursday gave every value one owner; today you lend values instead of giving
them away. You will finish a small crate, tested with plain cargo test on
your laptop, in which readers take shared slices, a writer takes an exclusive
slice and changes the caller's array in place, one function returns a borrowed
slice and needs a lifetime to say whose, and a small struct holds a &mut to
a counter. The tests check the values and the shape of the borrows: shared
borrows of one array coexist, an exclusive borrow ends when its function
returns, and the counter is readable directly again once the struct goes out
of scope.
Concepts you need¶
&shared vs&mutexclusive — Lecture §4.2 · Rust for Systems, Two kinds of borrow- Slices: a pointer and a length, no copy — Lecture §4.1 · Rust for Systems, Slices are borrows
- Aliasing XOR mutation — Lecture §5 · Rust for Systems, The aliasing rule
- Borrows end at their last use — Lecture §5.2 · Rust for Systems, The aliasing rule
- Lifetimes,
'a, and a struct that holds a reference — Lecture §6 · Rust for Systems, Lifetimes · The guard pattern - E0499, E0502, E0106 — Lecture §7 · Rust for Systems, Common compiler errors
Read before class¶
| What | Time |
|---|---|
| Lecture §4–§7 | 20 min |
| Rust for Systems §2 | 10 min |
Mental model¶
A borrow is a loan with a receipt. The owner keeps the value; the receipt says who may look, whether anyone may write, and when the loan is over.
let mut line = [b'h', b'i', 0, 0]; // `line` is the owner
let head = &line[..2]; // shared loan: pointer + length, no copy
let zeros = count_zeros(head); // last use of `head`: the loan ends here
upcase(&mut line); // exclusive loan, begins and ends on this line
struct Cursor<'a> { text: &'a [u8], at: usize }
let cur = Cursor { text: &line, at: 0 }; // `cur` may not outlive `line`
println!("{zeros} {}", cur.text[cur.at]);
It compiles because no two loans overlap illegally: the shared loan ends before
the exclusive one starts, and Cursor<'a> records that it points into
something it does not own. Kernels run on this shape: pages, disk blocks, and
console buffers travel as slices, and the spinlock guard in 37k_spinlocks is
a struct holding a reference, so "touch the data only while you hold the lock"
becomes a compiler check.
Check yourself¶
let a = &mut page; let b = &mut page; use_both(a, b);is rejected; with&pageit is fine. Why?Answer
Aliasing XOR mutation: any number of shared borrows may coexist, but a&mutmust be the only live path to the value. Two live&mutborrows is E0499.fn shorter(a: &str, b: &str) -> &strdoes not compile. What is missing, and what does adding<'a>to it promise?Answer
The result borrows from an input and the signature does not say which (E0106).'astates a relationship: both inputs live at least through region'a, and the result is valid no longer than that.- A struct holds a
&mut u64to a variablen. While that struct value is alive, may the function that ownsnreadndirectly?Answer
No: the exclusive borrow makes the struct the only path ton, so a direct read is E0502. After the struct's last use the borrow is over andnis usable directly again.
What "done" looks like¶
oslings run is green, then oslings submit before you leave. Not green? Submit anyway (substantial credit), then finish by Monday, Sep 7, 11:59 pm and submit again.
If you finish early¶
- Rustlings:
06_move_semantics, then16_lifetimes. - 100 Exercises To Learn Rust: chapter 3, the ownership and references sections; chapter 6, the slices sections.
- Lecture Practice Problem 4 and Problem 5: same skills, no tests to lean on.