Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Rust Refresher for Readers

This refresher is about reading, not writing: what a construct tells you when you see it in a review.

Ownership

You seeIt means
fn f(x: Thing)f takes ownership. The caller can’t use x afterwards.
fn f(x: &Thing)f borrows x read-only. The caller keeps ownership.
fn f(x: &mut Thing)f mutates x in place, with exclusive access.
let y = x.clone()A copy. Sometimes deliberate, sometimes not (see the Smell Catalog).

Traits

  • A trait is a named capability: “this type can be displayed”, “this type can be iterated”, that kind of thing.
  • impl Trait for Type says the type has the capability. A bound T: Trait says the caller needs it.
  • dyn Trait selects the concrete type at runtime. Generics select it at compile time.

Two questions for any Rust file

  1. Who owns which data, and for how long? Look at the types: which ones hold data and which ones only reference it.
  2. What can fail, and where does the failure surface? Look at the Results. If the design is honest, fallibility is visible in the signatures.

Warm-up

Answer the two questions for this code:

use std::collections::HashMap;

pub struct Inventory {
    parts: HashMap<String, u32>,
}

pub struct OutOfStock;

impl Inventory {
    pub fn part_count(&self, part: &str) -> Option<u32> {
        self.parts.get(part).copied()
    }

    pub fn take(&mut self, part: &str, n: u32) -> Result<(), OutOfStock> {
        match self.parts.get_mut(part) {
            Some(count) if *count >= n => {
                *count -= n;
                Ok(())
            }
            _ => Err(OutOfStock),
        }
    }

    pub fn into_report(self) -> String {
        let mut lines: Vec<String> = self
            .parts
            .iter()
            .map(|(name, count)| format!("{name}: {count}"))
            .collect();
        lines.sort();
        lines.join("\n")
    }
}