Expand description
Composable external iteration.
If you’ve found yourself with a collection of some kind, and needed toperform an operation on the elements of said collection, you’ll quickly runinto ‘iterators’. Iterators are heavily used in idiomatic Rust code, soit’s worth becoming familiar with them.
Before explaining more, let’s talk about how this module is structured:
§Organization
This module is largely organized by type:
- Traits are the core portion: these traits define what kind of iteratorsexist and what you can do with them. The methods of these traits are worthputting some extra study time into.
- Functions provide some helpful ways to create some basic iterators.
- Structs are often the return types of the various methods on thismodule’s traits. You’ll usually want to look at the method that createsthe
struct, rather than thestructitself. For more detail about why,see ‘Implementing Iterator’.
That’s it! Let’s dig into iterators.
§Iterator
The heart and soul of this module is theIterator trait. The core ofIterator looks like this:
An iterator has a method,next, which when called, returns anOption<Item>. Callingnext will returnSome(Item) as long as thereare elements, and once they’ve all been exhausted, will returnNone toindicate that iteration is finished. Individual iterators may choose toresume iteration, and so callingnext again may or may not eventuallystart returningSome(Item) again at some point (for example, seeTryIter).
Iterator’s full definition includes a number of other methods as well,but they are default methods, built on top ofnext, and so you getthem for free.
Iterators are also composable, and it’s common to chain them together to domore complex forms of processing. See theAdapters sectionbelow for more details.
§The three forms of iteration
There are three common methods which can create iterators from a collection:
iter(), which iterates over&T.iter_mut(), which iterates over&mut T.into_iter(), which iterates overT.
Various things in the standard library may implement one or more of thethree, where appropriate.
§Implementing Iterator
Creating an iterator of your own involves two steps: creating astruct tohold the iterator’s state, and then implementingIterator for thatstruct.This is why there are so manystructs in this module: there is one foreach iterator and iterator adapter.
Let’s make an iterator namedCounter which counts from1 to5:
// First, the struct:/// An iterator which counts from one to fivestructCounter { count: usize,}// we want our count to start at one, so let's add a new() method to help.// This isn't strictly necessary, but is convenient. Note that we start// `count` at zero, we'll see why in `next()`'s implementation below.implCounter {fnnew() -> Counter { Counter { count:0} }}// Then, we implement `Iterator` for our `Counter`:implIteratorforCounter {// we will be counting with usizetypeItem = usize;// next() is the only required methodfnnext(&mutself) ->Option<Self::Item> {// Increment our count. This is why we started at zero.self.count +=1;// Check to see if we've finished counting or not.ifself.count <6{Some(self.count) }else{None} }}// And now we can use it!letmutcounter = Counter::new();assert_eq!(counter.next(),Some(1));assert_eq!(counter.next(),Some(2));assert_eq!(counter.next(),Some(3));assert_eq!(counter.next(),Some(4));assert_eq!(counter.next(),Some(5));assert_eq!(counter.next(),None);Callingnext this way gets repetitive. Rust has a construct which cancallnext on your iterator, until it reachesNone. Let’s go over thatnext.
Also note thatIterator provides a default implementation of methods such asnth andfoldwhich callnext internally. However, it is also possible to write a custom implementation ofmethods likenth andfold if an iterator can compute them more efficiently without callingnext.
§for loops andIntoIterator
Rust’sfor loop syntax is actually sugar for iterators. Here’s a basicexample offor:
This will print the numbers one through five, each on their own line. Butyou’ll notice something here: we never called anything on our vector toproduce an iterator. What gives?
There’s a trait in the standard library for converting something into aniterator:IntoIterator. This trait has one method,into_iter,which converts the thing implementingIntoIterator into an iterator.Let’s take a look at thatfor loop again, and what the compiler convertsit into:
Rust de-sugars this into:
letvalues =vec![1,2,3,4,5];{letresult =matchIntoIterator::into_iter(values) {mutiter =>loop{letnext;matchiter.next() {Some(val) => next = val,None=>break, };letx = next;let() = {println!("{x}"); }; }, }; result}First, we callinto_iter() on the value. Then, we match on the iteratorthat returns, callingnext over and over until we see aNone. Atthat point, webreak out of the loop, and we’re done iterating.
There’s one more subtle bit here: the standard library contains aninteresting implementation ofIntoIterator:
In other words, allIterators implementIntoIterator, by justreturning themselves. This means two things:
- If you’re writing an
Iterator, you can use it with aforloop. - If you’re creating a collection, implementing
IntoIteratorfor itwill allow your collection to be used with theforloop.
§Iterating by reference
Sinceinto_iter() takesself by value, using afor loop to iterateover a collection consumes that collection. Often, you may want to iterateover a collection without consuming it. Many collections offer methods thatprovide iterators over references, conventionally callediter() anditer_mut() respectively:
letmutvalues =vec![41];forxinvalues.iter_mut() {*x +=1;}forxinvalues.iter() {assert_eq!(*x,42);}assert_eq!(values.len(),1);// `values` is still owned by this function.If a collection typeC providesiter(), it usually also implementsIntoIterator for&C, with an implementation that just callsiter().Likewise, a collectionC that providesiter_mut() generally implementsIntoIterator for&mut C by delegating toiter_mut(). This enables aconvenient shorthand:
letmutvalues =vec![41];forxin&mutvalues {// ^ same as `values.iter_mut()`*x +=1;}forxin&values {// ^ same as `values.iter()`assert_eq!(*x,42);}assert_eq!(values.len(),1);While many collections offeriter(), not all offeriter_mut(). Forexample, mutating the keys of aHashSet<T> could put the collectioninto an inconsistent state if the key hashes change, so this collectiononly offersiter().
§Adapters
Functions which take anIterator and return anotherIterator areoften called ‘iterator adapters’, as they’re a form of the ‘adapterpattern’.
Common iterator adapters includemap,take, andfilter.For more, see their documentation.
If an iterator adapter panics, the iterator will be in an unspecified (butmemory safe) state. This state is also not guaranteed to stay the sameacross versions of Rust, so you should avoid relying on the exact valuesreturned by an iterator which panicked.
§Laziness
Iterators (and iteratoradapters) arelazy. This means thatjust creating an iterator doesn’tdo a whole lot. Nothing really happensuntil you callnext. This is sometimes a source of confusion whencreating an iterator solely for its side effects. For example, themapmethod calls a closure on each element it iterates over:
This will not print any values, as we only created an iterator, rather thanusing it. The compiler will warn us about this kind of behavior:
warning: unused result that must be used: iterators are lazy anddo nothing unless consumedThe idiomatic way to write amap for its side effects is to use afor loop or call thefor_each method:
Another common way to evaluate an iterator is to use thecollectmethod to produce a new collection.
§Infinity
Iterators do not have to be finite. As an example, an open-ended range isan infinite iterator:
It is common to use thetake iterator adapter to turn an infiniteiterator into a finite one:
This will print the numbers0 through4, each on their own line.
Bear in mind that methods on infinite iterators, even those for which aresult can be determined mathematically in finite time, might not terminate.Specifically, methods such asmin, which in the general case requiretraversing every element in the iterator, are likely not to returnsuccessfully for any infinite iterators.
Macros§
- iter
Experimental - Creates a new closure that returns an iterator where each iteration steps the givengenerator to the next
yieldstatement.
Structs§
- Chain
- An iterator that links two iterators together, in a chain.
- Cloned
- An iterator that clones the elements of an underlying iterator.
- Copied
- An iterator that copies the elements of an underlying iterator.
- Cycle
- An iterator that repeats endlessly.
- Empty
- An iterator that yields nothing.
- Enumerate
- An iterator that yields the current count and the element during iteration.
- Filter
- An iterator that filters the elements of
iterwithpredicate. - Filter
Map - An iterator that uses
fto both filter and map elements fromiter. - FlatMap
- An iterator that maps each element to an iterator, and yields the elementsof the produced iterators.
- Flatten
- An iterator that flattens one level of nesting in an iterator of thingsthat can be turned into iterators.
- FromFn
- An iterator where each iteration calls the provided closure
F: FnMut() -> Option<T>. - Fuse
- An iterator that yields
Noneforever after the underlying iteratoryieldsNoneonce. - Inspect
- An iterator that calls a function with a reference to each element beforeyielding it.
- Map
- An iterator that maps the values of
iterwithf. - MapWhile
- An iterator that only accepts elements while
predicatereturnsSome(_). - Once
- An iterator that yields an element exactly once.
- Once
With - An iterator that yields a single element of type
Abyapplying the provided closureF: FnOnce() -> A. - Peekable
- An iterator with a
peek()that returns an optional reference to the nextelement. - Repeat
- An iterator that repeats an element endlessly.
- RepeatN
- An iterator that repeats an element an exact number of times.
- Repeat
With - An iterator that repeats elements of type
Aendlessly byapplying the provided closureF: FnMut() -> A. - Rev
- A double-ended iterator with the direction inverted.
- Scan
- An iterator to maintain state while iterating another iterator.
- Skip
- An iterator that skips over
nelements ofiter. - Skip
While - An iterator that rejects elements while
predicatereturnstrue. - StepBy
- An iterator for stepping iterators by a custom amount.
- Successors
- An iterator which, starting from an initial item,computes each successive item from the preceding one.
- Take
- An iterator that only iterates over the first
niterations ofiter. - Take
While - An iterator that only accepts elements while
predicatereturnstrue. - Zip
- An iterator that iterates two other iterators simultaneously.
- Array
Chunks Experimental - An iterator over
Nelements of the iterator at a time. - ByRef
Sized Experimental - Like
Iterator::by_ref, but requiringSizedso it can forward generics. - From
Coroutine Experimental - An iterator over the values yielded by an underlying coroutine.
- Intersperse
Experimental - An iterator adapter that places a separator between all elements.
- Intersperse
With Experimental - An iterator adapter that places a separator between all elements.
- MapWindows
Experimental - An iterator over the mapped windows of another iterator.
Traits§
- Double
Ended Iterator - An iterator able to yield elements from both ends.
- Exact
Size Iterator - An iterator that knows its exact length.
- Extend
- Extend a collection with the contents of an iterator.
- From
Iterator - Conversion from an
Iterator. - Fused
Iterator - An iterator that always continues to yield
Nonewhen exhausted. - Into
Iterator - Conversion into an
Iterator. - Iterator
- A trait for dealing with iterators.
- Product
- Trait to represent types that can be created by multiplying elements of aniterator.
- Sum
- Trait to represent types that can be created by summing up an iterator.
- Step
Experimental - Objects that have a notion ofsuccessor andpredecessor operations.
- Trusted
Len Experimental - An iterator that reports an accurate length using size_hint.
- Trusted
Step Experimental - A type that upholds all invariants of
Step.
Functions§
- chain
- Converts the arguments to iterators and links them together, in a chain.
- empty
- Creates an iterator that yields nothing.
- from_fn
- Creates an iterator with the provided closure
F: FnMut() -> Option<T>as itsnextmethod. - once
- Creates an iterator that yields an element exactly once.
- once_
with - Creates an iterator that lazily generates a value exactly once by invokingthe provided closure.
- repeat
- Creates a new iterator that endlessly repeats a single element.
- repeat_
n - Creates a new iterator that repeats a single element a given number of times.
- repeat_
with - Creates a new iterator that repeats elements of type
Aendlessly byapplying the provided closure, the repeater,F: FnMut() -> A. - successors
- Creates an iterator which, starting from an initial item,computes each successive item from the preceding one.
- zip
- Converts the arguments to iterators and zips them.
- from_
coroutine Experimental - Creates a new iterator where each iteration calls the provided coroutine.