Iterators

From Rust Community Wiki
Jump to navigation Jump to search

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.

Example[edit | edit source]

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 loops[edit | edit source]

IntoIteratorThis links to official Rust documentation 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 VecThis links to official Rust documentation, OptionThis links to official Rust documentation, ResultThis links to official Rust documentation 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.

Example[edit | edit source]

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

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

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

FromIterator and collect()[edit | edit source]

The FromIteratorThis links to official Rust documentation 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()This links to official Rust documentation 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.

Example[edit | edit source]

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 documentation[edit | edit source]

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 iterators[edit | edit source]

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 FusedIteratorThis links to official Rust documentation trait guarantees this, and it is implemented by all iterators that have this behavior. Additionally, any iterator can become fused by calling Iterator::fuse()This links to official Rust documentation 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 iterators[edit | edit source]

Sometimes it's necessary to iterate over something in reverse direction. Iterators that implement the DoubleEndedIteratorThis links to official Rust documentation 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.

Example[edit | edit source]

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

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

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

Adapters[edit | edit source]

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

allThis links to official Rust documentation
anyThis links to official Rust documentation

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

chainThis links to official Rust documentation

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

cmpThis links to official Rust documentation
partial_cmpThis links to official Rust documentation
geThis links to official Rust documentation
gtThis links to official Rust documentation
leThis links to official Rust documentation
ltThis links to official Rust documentation
eqThis links to official Rust documentation
neThis links to official Rust documentation

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

collectThis links to official Rust documentation

Collects the elements into a new collection, using the FromIteratorThis links to official Rust documentation trait. yes

copiedThis links to official Rust documentation
clonedThis links to official Rust documentation

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

countThis links to official Rust documentation

Returns the number of elements in the iterator. yes

minThis links to official Rust documentation
min_byThis links to official Rust documentation
min_by_keyThis links to official Rust documentation
maxThis links to official Rust documentation
max_byThis links to official Rust documentation
max_by_keyThis links to official Rust documentation

Gets the minimum or maximum element of the iterator.

The *_by functions accept a closure that compares two elements and returns an OrderingThis links to official Rust documentation.

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

sumThis links to official Rust documentation
productThis links to official Rust documentation

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

cycleThis links to official Rust documentation

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

enumerateThis links to official Rust documentation

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

filterThis links to official Rust documentation

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

findThis links to official Rust documentation

Searches for an element that satisfies a predicate. yes

flattenThis links to official Rust documentation

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_mapThis links to official Rust documentation
find_mapThis links to official Rust documentation
flat_mapThis links to official Rust documentation

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

foldThis links to official Rust documentation

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_eachThis links to official Rust documentation

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

fuseThis links to official Rust documentation

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

inspectThis links to official Rust documentation

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

is_partitionedThis links to official Rust documentation

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_sortedThis links to official Rust documentation
is_sorted_byThis links to official Rust documentation
is_sorted_by_keyThis links to official Rust documentation

Checks if the elements of this iterator are sorted. yes

lastThis links to official Rust documentation

Returns the last element.

Note that this can be expensive, unless the iterator implements DoubleEndedIteratorThis links to official Rust documentation.

yes

mapThis links to official Rust documentation

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

nthThis links to official Rust documentation

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

partitionThis links to official Rust documentation

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

peekableThis links to official Rust documentation

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

positionThis links to official Rust documentation
rpositionThis links to official Rust documentation

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

rposition searches from the right. This is only possible if the iterator implements DoubleEndedIteratorThis links to official Rust documentation.

yes

revThis links to official Rust documentation

Returns an iterator where the order of elements is reversed. This is only possible if the iterator implements DoubleEndedIteratorThis links to official Rust documentation. no

scanThis links to official Rust documentation

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

skipThis links to official Rust documentation
skip_whileThis links to official Rust documentation

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

step_byThis links to official Rust documentation

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

takeThis links to official Rust documentation
take_whileThis links to official Rust documentation

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

try_findThis links to official Rust documentation
try_foldThis links to official Rust documentation
try_for_eachThis links to official Rust documentation

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

zipThis links to official Rust documentation

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

unzipThis links to official Rust documentation

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