Iterators

Iterators in Rust provide a way to lazily evaluate a sequence of values. All iterators implement the IteratorThis links to official Rust documentation trait, which has one associated type, ItemThis links to official Rust documentation, and one method, next()This links to official Rust documentation, with the following signature:

fn next(&mut self) -> Option<Self::Item>;

Calling next() progresses the iterator and returns Some with the next value. This is often called consuming the next value. When the iterator is finished, calling next() returns None.

Iterators are analogous to the List monad in Haskell, and iterators in many other languages like Python.

ExampleEdit

let a = [1, 2, 3];

let mut iter = a.iter();

// A call to next() returns the next value...
assert_eq!(Some(&1), iter.next());
assert_eq!(Some(&2), iter.next());
assert_eq!(Some(&3), iter.next());

// ... and then None once it's over.
assert_eq!(None, iter.next());

IntoIterator and for loopsEdit

IntoIterator  is a trait that converts any collection into an iterator over its elements. It is implemented for all collection and collection-like types in the standard library, such as Vec , Option , Result  and slices. It is also implemented for all iterators as the identity function.

It is most useful in for loops, which can iterate over any type that implements IntoIterator. It first converts the variable into an iterator and then repeatedly calls its next() method until it returns None - for pattern in iterator is therefore logically equivalent to while let Some(pattern) = iterator.next(), but looks cleaner and clearer.

ExampleEdit

let v: Vec<i32> = vec![1, 2, 3];

for num in v {
    println!("{}", num);
}

// This prints:
// 1
// 2
// 3

FromIterator and collect()Edit

The FromIterator  is the opposite of IntoIterator - it converts an iterator into a collection instead of the other way around. It is primarily not used directly, but rather through the iterator's collect()  method.

FromIterator is implemented for all collection types, such as String, Vec, HashMap etc, but is also implemented for Option and Result, where it takes an iterator of Options and Results and 'flattens' it into a single Option or Result.

ExampleEdit

let v: Vec<i32> = [1, 2, 3].iter().map(|&i| i + 1).collect();

for num in v {
    println!("{}", num);
}

// This prints:
// 2
// 3
// 4

It can also be used to convert one collection type into another:

let v: Vec<(i32, i32)> = vec![
    (4, 2),
    (5, 3),
    (6, 4),
];

// convert the Vec to a HashMap:
let hm: HashMap<i32, i32> = v.into_iter().collect();

Flattening Options:

assert_eq!(
    [Some(5), Some(6), Some(7)]
        .iter()
        .copied()
        .collect::<Option<Vec<_>>(),
    Some(vec![5, 6, 7]),
);
assert_eq!(
    [Some(5), Some(6), None]
        .iter()
        .copied()
        .collect::<Option<Vec<_>>(),
    None,
);

ExactSizeIteratorThis links to official Rust documentationEdit

In some situations, Rust can produce more efficient code if it knows the number of elements of the iterator up front. For example, when collecting into a Vec, Rust can set the correct capacity to start with and avoid reallocation. The ExactSizeIterator trait provides this, and so iterators that implement this can be collected very efficiently.

Unless you are manually implementing an iterator, you don't generally have to worry about whether ExactSizeIterator is implemented or not — standard library iterators implement it wherever it is possible.

Fused iteratorsEdit

Calling next() on an iterator that has already returned None once has unspecified (but not undefined) behavior. It might return None, Some, or even panic. However, it can be useful to have an iterator that will continue to return None after finishing. The FusedIterator  trait guarantees this, and it is implemented by all iterators that have this behavior. Additionally, any iterator can become fused by calling Iterator::fuse()  on it, which for already-fused iterators is a no-op and for unfused iterators will keep track of whether the iterator has ended or not.

Double-ended iteratorsEdit

Sometimes it's necessary to iterate over something in reverse direction. Iterators that implement the DoubleEndedIterator  trait require a next_back() method which consumes an element from the end of the iterator. Double ended iterators also provide a rev() method, which reverses the iterator. This means that calling next() now consumes an element from the end of the iterator, and next_back() consumes an element from the start.

ExampleEdit

let v: Vec<i32> = vec![1, 2, 3];

for num in v.into_iter().rev() {
    println!("{}", num);
}

// This prints:
// 3
// 2
// 1

AdaptersEdit

By itself, looping through all elements of an iterator in order is a fairly basic operation. The true power of iterators comes from adapters — additional methods on the Iterator trait, which perform various transformations on the iterator. Since those are defined and implemented by default on the Iterator trait itself, they are automatically usable with any iterator.

Some adapters take an iterator and return one final value from it. Those are commonly referred to as consuming adapters, since the consume the iterator and all of the elements it produces. The opposite behavior is known as non-consuming adapters — those take an iterator and create a new one based on the one which has been provided. Iterating through the new iterator will then perform various transformations on the values.

Standard library adapters
Functions Description Consumes

all 
any 

Check if a predicate is true for all elements or at least one element of the iterator.
assert!((2..8).all(|n| n > 0));
assert!((2..8).any(|n| n % 2 == 0));
yes

chain 

Combines the iterator with another iterator (or something that implements IntoIterator). The returned iterator first yields the elements of the first iterator and then the elements of the second iterator.
for n in (0..4).chain(7..=9) {
    print!("{}", n); // prints 0123789
}
no

cmp 
partial_cmp 
ge 
gt 
le 
lt 
eq 
ne 

Compares the iterator with another iterator (or something that implements IntoIterator). yes

collect 

Collects the elements into a new collection, using the FromIterator  trait. yes

copied 
cloned 

Converts an iterator over references to an iterator over owned values by dereferencing or cloning them. no

count 

Returns the number of elements in the iterator. yes

min 
min_by 
min_by_key 
max 
max_by 
max_by_key 

Gets the minimum or maximum element of the iterator.

The *_by functions accept a closure that compares two elements and returns an Ordering .

The *_by_key functions accept a closure that takes an element and returns a key used for the comparison.

assert_eq!((1..=4).max(), Some(4));

let max = "1,2,3,-4"
    .split(",")
    .max_by_key(|s| s.parse::<i32>().unwrap());
assert_eq!(max, Some("3"));
yes

sum 
product 

Combines all elements of the iterator with a mathematical operation; the elements are either added (sum) or multiplied (product).
assert_eq!(15, (1..=5).sum());
assert_eq!(120, (1..=5).product());
yes

cycle 

Repeats the iterator endlessly.
assert_eq!(
    (1..=3).cycle().take(10).collect::<Vec<_>>(),
    vec![1, 2, 3, 1, 2, 3, 1, 2, 3, 1],
);
no

enumerate 

Adds a zero-based index to each element of the iterator.
assert_eq!(
    (2..=4).enumerate().collect::<Vec<_>>(),
    vec![(0, 2), (1, 3), (2, 4)],
);
no

filter 

Creates an iterator that contains only the elements from the original iterator that fulfill a certain condition.
assert_eq!(
    (0..10).filter(|n| n % 3 == 0).collect::<Vec<_>>(),
    vec![0, 3, 6, 9],
)
no

find 

Searches for an element that satisfies a predicate. yes

flatten 

Flattens a nested iterator by one level. The inner type has to implement IntoIterator.

For example, flattening an impl Iterator<Item = Option<i32>> produces an impl Iterator<Item = i32>.

no

filter_map 
find_map 
flat_map 

Combinations of filter + map, find + map and flatten + map, respectively. no
yes
no

fold 

An iterator method that applies a function, producing a single, final value.
// calculate (((1000 / 2) / 3) / 4) / 5
let result = (2..=5).fold(1000, |acc, n| acc / n);
assert_eq!(result, 8);
yes

for_each 

An alternative to a for loop. This calls a closure on each element of the iterator. yes

fuse 

This returns a fused iterator, i.e. an iterator that always returns None after the first None. no

inspect 

Calls a closure on each element when it is yielded, but doesn't modify it. no

is_partitioned 

Checks if the elements of this iterator are partitioned according to the given predicate, such that all those that return true precede all those that return false. yes

is_sorted 
is_sorted_by 
is_sorted_by_key 

Checks if the elements of this iterator are sorted. yes

last 

Returns the last element.

Note that this can be expensive, unless the iterator implements DoubleEndedIterator .

yes

map 

Returns a new iterator where each element is transformed using a closure.
assert_eq!(
    (1..=3).map(|n| n * 2).collect::<Vec<_>>(),
    vec![2, 4, 6],
);
no

nth 

Returns the n-th element, starting at 0. This consumes n elements of the iterator.
assert_eq!((2..8).nth(3), Some(5));
yes

partition 

Converts the iterator into two collections. It accepts a predicate; elements for which the predicate returns true are added to the first collection, the other elements are added to the second collection. yes

peekable 

Creates an iterator which can use peek to look at the next element of the iterator without consuming it. no

position 
rposition 

Searches for an element in an iterator, returning its index.

rposition searches from the right. This is only possible if the iterator implements DoubleEndedIterator .

yes

rev 

Returns an iterator where the order of elements is reversed. This is only possible if the iterator implements DoubleEndedIterator . no

scan 

An iterator adaptor similar to fold that holds internal state and produces a new iterator. no

skip 
skip_while 

Creates an iterator that skips the first n elements, or skips elements while a predicate returns true. yes

step_by 

Creates an iterator starting at the same point, but stepping by the given amount at each iteration. no

take 
take_while 

Creates an iterator that yields its first n elements, or yields elements only until a predicate returns false. no

try_find 
try_fold 
try_for_each 

Fallible variants of find, fold and for_each. yes
no
yes

zip 

Creates a new iterator where each element of two iterators is combined into a tuple. no

unzip 

Does the opposite of zip, it converts an iterator of pairs into a pair of collections. yes