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.
-
IntoIterwraps the list and delegatesIterator::nexttopop_front.DoubleEndedIterator::next_backcallspop_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() } } -
Iter<T>would want to yield&T. To produce one, it'd need to callborrow()on the current node's RefCell, then return a reference into it. But theRefguard has to outlive the reference, andIterator::nextreturns a value, not a guard — there is nowhere for the guard to live. You can yieldRef<T>instead, but then you've broken theIteratortrait'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 // ... // } -
IterMutis worse: it would need a liveRefMutguard per node, and walking the list would require holding aRefMutfor the current node while reaching into itsnextlink to get to the next node — which itself requires anotherRefMuton the same chain. The runtime borrow checker would either panic or you'd have to architect around it withmem::replaceandRc::clone. We won't write it; the takeaway is thatRc<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.