18
Drop
Same recursive-drop hazard as the Box list, with a wrinkle. Dropping an Rc<Node> only actually frees the node when the refcount hits zero — if another list still shares this tail, drop is a single decrement and we stop. But if we are the last owner of a long uniquely-held list, the auto-derived destructor recurses one frame per node and overflows.
- We can't use
mem::replaceto walk the list because we don't own the node — we only hold anRc<Node>. The right tool isRc::try_unwrap: if the refcount is exactly one, it consumes theRcand gives us the innerNodeby value; otherwise it hands theRcback. We loop, unwrapping where we're the sole owner and stopping the moment a node is shared.use std::mem; impl<T> Drop for List<T> { fn drop(&mut self) { let mut head = self.head.take(); while let Some(node) = head { if let Ok(mut node) = Rc::try_unwrap(node) { // we were the sole owner — keep walking. head = node.next.take(); } else { // someone else still holds this node; stop. break; } } } } - Trace it.
head.take()pulls the head out as anOption<Rc<Node>>, leavingNonebehind.Rc::try_unwrap(node)succeeds (refcount was 1), yielding theNodeby value. Wetakeitsnextand loop. Whentry_unwrapfails, we break — the remaining nodes are someone else's problem, and dropping theRcwe couldn't unwrap is just one decrement.// uniquely-held: 3 -> 2 -> 1 -> Nil (refcounts all 1) // iter 1: try_unwrap node{3} -> Ok; head = Some(node{2}) // iter 2: try_unwrap node{2} -> Ok; head = Some(node{1}) // iter 3: try_unwrap node{1} -> Ok; head = None; loop exits. // // shared tail: 5 -> [2 -> 1] where [2 -> 1] is also held by another list // iter 1: try_unwrap node{5} -> Ok; head = Some(node{2}) // iter 2: try_unwrap node{2} -> Err (refcount 2); break. // Rc<Node{2}> drops here -> refcount goes 2 -> 1. Done.