45
An Introduction To Cursors
A cursor is a position inside a sequence — like the blinking insertion point in a text editor — that you can advance, retreat, and edit at. It is what Iterator is not: bidirectional, stable across mutations, and able to splice. The standard library exposes LinkedList::cursor_front_mut() (unstable) for exactly this.
- Why iterators don't fit. A
&mutiterator hands out&mut Treferences whose lifetimes outlive each call tonext. To insert or remove a node mid-iteration, the iterator would have to invalidate or reissue references, which the borrow checker doesn't allow. Cursors solve this by exposing&mut LinkedList<T>semantics at a single position rather than streaming references.// iterator: stream of references, can't edit around them for x in list.iter_mut() { *x += 1; // can't list.push_back(...) here — list is borrowed by iter } // cursor: one position, full mutation rights let mut c = list.cursor_front_mut(); while let Some(x) = c.current() { if *x == 0 { c.remove_current(); } else { c.move_next(); } } - The std model:
CursorMut<'a, T>borrows&'a mut LinkedList<T>and tracks a position that can be either at a node or at a special "ghost" position between back and front (representing the gap that wraps around in a circular view). Movement past either end lands on the ghost; one more step lands back on the other end.// list: A <-> B <-> C // states: [G] A [.] B [.] C [G] (G = ghost) // // move_next from C lands on ghost. // move_next from ghost lands on A. // current() returns None at the ghost. // // insert_after at ghost == push_front (effectively). // insert_before at ghost == push_back (effectively).