Learn Rust With Entirely Too Many Linked Lists
26

Iteration

IntoIter is trivial — next calls pop_front and consumes from one end. The other two iterators, Iter and IterMut, are essentially impossible to write the way the rest of the standard library writes them, because every yielded item would need to carry a live Ref or RefMut guard.

  1. IntoIter wraps the list and delegates Iterator::next to pop_front. DoubleEndedIterator::next_back calls pop_back. Each call walks one end, ending when the list is empty.
    pub struct IntoIter<T>(List<T>);
    
    impl<T> List<T> {
        pub fn into_iter(self) -> IntoIter<T> { IntoIter(self) }
    }
    
    impl<T> Iterator for IntoIter<T> {
        type Item = T;
        fn next(&mut self) -> Option<T> { self.0.pop_front() }
    }
    
    impl<T> DoubleEndedIterator for IntoIter<T> {
        fn next_back(&mut self) -> Option<T> { self.0.pop_back() }
    }
  2. Iter<T> would want to yield &T. To produce one, it'd need to call borrow() on the current node's RefCell, then return a reference into it. But the Ref guard has to outlive the reference, and Iterator::next returns a value, not a guard — there is nowhere for the guard to live. You can yield Ref<T> instead, but then you've broken the Iterator trait's idiomatic shape and every consumer pays the price.
    // What you'd want — does not work cleanly:
    // impl<'a, T> Iterator for Iter<'a, T> {
    //     type Item = &'a T;          // can't: needs a Ref guard somewhere
    //     fn next(&mut self) -> Option<&'a T> { ... }
    // }
    //
    // What you can do — leaks RefCell into the iterator API too:
    // impl<T> Iterator for Iter<T> {
    //     type Item = Ref<T>;          // every consumer now imports std::cell::Ref
    //     ...
    // }
  3. IterMut is worse: it would need a live RefMut guard per node, and walking the list would require holding a RefMut for the current node while reaching into its next link to get to the next node — which itself requires another RefMut on the same chain. The runtime borrow checker would either panic or you'd have to architect around it with mem::replace and Rc::clone. We won't write it; the takeaway is that Rc<RefCell<T>> is the wrong primitive for an iterating collection.
    // We don't implement Iter or IterMut. The design can't support them
    // without leaking Ref<T>/RefMut<T> into every caller's signature.
    // In practice this is the moment you decide Rc<RefCell<T>> is the
    // wrong representation for a deque.