05
Pop
Pop is push run backwards: take the head node, hand the caller its element, splice the rest of the list back into self.head. The empty case has to return something, which is what Option<T> is for.
- First instinct:
match &self.head. Empty → returnNone. More → return the element. The catch:&self.headis a borrow, which prevents you from also assigning toself.headinside the same arm.pub fn pop(&mut self) -> Option<i32> { match &self.head { Link::Empty => None, Link::More(node) => { // we want node.elem AND to set self.head = node.next, // but the borrow on self.head is still live — won't compile. Some(node.elem) } } } - Same trick as push:
mem::replaceto take the head out by value, leavingLink::Emptybehind. Now we own the old head and can disassemble it without fighting borrows.use std::mem; pub fn pop(&mut self) -> Option<i32> { match mem::replace(&mut self.head, Link::Empty) { Link::Empty => None, Link::More(node) => { self.head = node.next; Some(node.elem) } } } - When
nodefalls out of scope at the end of the arm, theBox<Node>is dropped and the heap allocation is freed. The element was already moved out into the return value, so there's no double-free or leak.let mut list = List::new(); list.push(1); list.push(2); assert_eq!(list.pop(), Some(2)); assert_eq!(list.pop(), Some(1)); assert_eq!(list.pop(), None);