Skip to content

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

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

  1. let a = &mut page; let b = &mut page; use_both(a, b); is rejected; with &page it is fine. Why?
    AnswerAliasing XOR mutation: any number of shared borrows may coexist, but a &mut must be the only live path to the value. Two live &mut borrows is E0499.
  2. fn shorter(a: &str, b: &str) -> &str does not compile. What is missing, and what does adding <'a> to it promise?
    AnswerThe result borrows from an input and the signature does not say which (E0106). 'a states a relationship: both inputs live at least through region 'a, and the result is valid no longer than that.
  3. A struct holds a &mut u64 to a variable n. While that struct value is alive, may the function that owns n read n directly?
    AnswerNo: the exclusive borrow makes the struct the only path to n, so a direct read is E0502. After the struct's last use the borrow is over and n is 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