24
Peek
Peek wants to return Option<&T> — a borrow of the head element without taking it. We can't. The element lives inside a RefCell, and the only way to read across a RefCell is through a Ref<T> guard. The RefCell type leaks into our public API.
-
RefCell::borrow()returns aRef<'_, T>— a smart pointer that derefs to&Tand bumps an internal read-borrow counter. The counter decrements on drop. Returning&Tdirectly out of aborrow()would let the caller hold the reference past the guard's lifetime, which would let you violate the borrow rules. The API forces you to keep the guard.use std::cell::Ref; pub fn peek_front(&self) -> Option<Ref<T>> { self.head.as_ref().map(|node| { Ref::map(node.borrow(), |n| &n.elem) }) } -
Ref::mapprojects the guard. It takesRef<'_, A>and a closure&A -> &B, returnsRef<'_, B>— same guard, narrower view. We use it to convertRef<Node<T>>intoRef<T>so callers don't see the Node type at all. They still seeRef, though.let mut list = List::new(); list.push_front("hello"); { let head: Ref<&str> = list.peek_front().unwrap(); assert_eq!(*head, "hello"); } // guard drops here, RefCell is unborrowed - This is where the design admits defeat.
Option<Ref<T>>in the public signature means callers must importstd::cell::Ref, must understand RefCell semantics, and must be careful not to hold the guard across calls that would re-borrow the same cell. We are exporting our internal storage choice as part of our type signature.// The leak — compare: // std::collections::VecDeque::front(&self) -> Option<&T> // our List::peek_front(&self) -> Option<Ref<T>>