Learn Rust With Entirely Too Many Linked Lists
11

Peek

peek returns a reference to the head element without removing it: Option<&T>. The fight here is going from &Option<Box<Node<T>>> to Option<&T> without moving anything. That's what as_ref and as_deref exist for.

  1. Option::as_ref converts &Option<T> into Option<&T>. Then map lets us reach into the Box and grab &node.elem. Box<T> derefs to T, so &node.elem is &T.
    impl<T> List<T> {
        pub fn peek(&self) -> Option<&T> {
            self.head.as_ref().map(|node| &node.elem)
        }
    }
  2. as_deref is the convenience version that combines as_ref with a Deref. On Option<Box<Node<T>>>, as_deref() gives you Option<&Node<T>> directly — useful when you want to skip past the Box indirection in one call. We'll lean on this shape in the iterators.
    // equivalent shapes:
    let a: Option<&Node<T>> = self.head.as_ref().map(|b| &**b);
    let b: Option<&Node<T>> = self.head.as_deref();
  3. peek_mut is the mirror image: as_mut on Option, then map to a &mut node.elem. The signature returns Option<&mut T>, which the caller can use to overwrite the head element in place.
    impl<T> List<T> {
        pub fn peek_mut(&mut self) -> Option<&mut T> {
            self.head.as_mut().map(|node| &mut node.elem)
        }
    }
    
    let mut list: List<i32> = List::new();
    list.push(1);
    if let Some(v) = list.peek_mut() { *v = 42; }
    assert_eq!(list.peek(), Some(&42));