Learn Rust With Entirely Too Many Linked Lists
09

Option

Look at Link from last chapter. Empty or Box<Node>. That's Option<Box<Node>> with the names changed. The standard library's Option already has every helper we hand-rolled with mem::replace and match.

  1. Drop Link entirely. Option<Box<Node>> is the same shape — one tag bit, one pointer payload — and Rust knows the null-pointer optimization, so it's still one machine word.
    pub struct List {
        head: Link,
    }
    
    type Link = Option<Box<Node>>;
    
    struct Node {
        elem: i32,
        next: Link,
    }
  2. Option::take is mem::replace(&mut x, None) with a shorter name. It pulls the value out and leaves None in place. Every mem::replace call in push, pop, and drop becomes a .take().
    pub fn push(&mut self, elem: i32) {
        let new_node = Box::new(Node {
            elem,
            next: self.head.take(),
        });
        self.head = Some(new_node);
    }
  3. Option::map runs a closure on the inner value if there is one and gives you back a new Option. Our two-arm match in pop collapses to a single line.
    pub fn pop(&mut self) -> Option<i32> {
        self.head.take().map(|node| {
            self.head = node.next;
            node.elem
        })
    }