Iterator
.
None
when iteration is finished. Individual iterator
implementations may choose to resume iteration, and so calling next()
again may or may not eventually start returning Some(Item)
again at some
point.
next
repeatedly until None
is encountered,
returning the number of times it saw Some
. Note that next
has to be
called at least once even if the iterator does not have any elements.
Bounded::::MAX
elements either produces the
wrong result or panics.
Bounded::::MAX
elements.
None
. While
doing so, it keeps track of the current element. After None
is
returned, last()
will then return the last element it saw.
n
elements.
This method will eagerly skip n
elements by calling next
up to n
times until None
is encountered.
advance_by(n)
will return Ok(())
if the iterator successfully advances by
n
elements, or a Err(NonZero)
with value k
if None
is encountered,
where k
is remaining number of steps that could not be advanced because the iterator ran
out.
If self
is empty and n
is non-zero, then this returns Err(n)
.
Otherwise, k
is always less than n
.
n
th element of the iterator.
Like most indexing operations, the count starts from zero, so nth(0)
returns the first value, nth(1)
the second, and so on.
Note that all preceding elements, as well as the returned element, will be
consumed from the iterator. That means that the preceding elements will be
discarded, and also that calling nth(0)
multiple times on the same iterator
will return different elements.
nth()
will return None
if n
is greater than or equal to the length of the
iterator.
nth()
multiple times doesn’t rewind the iterator:
None
if there are less than n + 1
elements:
map()
transforms one iterator into another, by means of its argument:
something that implements FnOnce
. It produces a new iterator which
calls this closure on each element of the original iterator.
If you are good at thinking in types, you can think of map()
like this:
If you have an iterator that gives you elements of some type A
, and
you want an iterator of some other type B
, you can use map()
,
passing a closure that takes an A
and returns a B
.
map()
is conceptually similar to a for
loop. However, as map()
is
lazy, it is best used when you’re already working with other iterators.
If you’re doing some sort of looping for a side effect, it’s considered
more idiomatic to use for
than map()
.
for
to map()
:
(i, val)
, where i
is the
current index of iteration and val
is the value returned by the
iterator.
enumerate()
keeps its count as a usize
.
Bounded::::MAX
elements will always panic.
usize
.
fold()
takes two arguments: an initial value, and a closure with two
arguments: an ‘accumulator’, and an element. The closure returns the value that
the accumulator should have for the next iteration.
The initial value is the value the accumulator will have on the first
call.
After applying this closure to every element of the iterator, fold()
returns the accumulator.
Folding is useful whenever you have a collection of something, and want
to produce a single value from it.
Note: fold()
, and similar methods that traverse the entire iterator,
might not terminate for infinite iterators, even on traits for which a
result is determinable in finite time.
Note: fold()
combines elements in a left-associative fashion. For associative
operators like +
, the order the elements are combined in is not important, but for
non-associative operators like -
the order will affect the final result.
for
loop implementation.
In particular, try to have this call fold()
on the internal parts
from which this iterator is composed.
element | acc | x | result |
---|---|---|---|
0 | |||
1 | 0 | 1 | 1 |
2 | 1 | 2 | 3 |
3 | 3 | 3 | 6 |
6
.
It’s common for people who haven’t used iterators a lot to
use a for
loop with a list of things to build up a result. Those
can be turned into fold()
s:
any()
takes a closure that returns true
or false
. It applies this closure to each
element of the iterator, and if any of them return true
, then so does any()
. If they all
return false
, it returns false
.
any()
is short-circuiting; in other words, it will stop processing as soon as it finds a
true
, given that no matter what else happens, the result will also be true
.
An empty iterator returns false
.
all()
takes a closure that returns true
or false
. It applies this closure to each
element of the iterator, and if all of them return true
, then so does all()
. If any
of them return false
, it returns false
.
all()
is short-circuiting; in other words, it will stop processing as soon as it finds a
false
, given that no matter what else happens, the result will also be false
.
An empty iterator returns true
.
find()
takes a closure that returns true
or false
. It applies
this closure to each element of the iterator as a snapshot, and if
any of them return true
, then find()
returns Some(element)
.
If they all return false
, it returns None
.
find()
is short-circuiting; in other words, it will stop processing
as soon as the closure returns true
.
true
:
iter.find(f)
is equivalent to iter.filter(f).next()
.
true
or false
. The returned
iterator will yield only the elements for which the closure returns
true
.
iter.filter(f).next()
is equivalent to iter.find(f)
.
zip()
returns a new iterator that will iterate over two other
iterators, returning a tuple where the first element comes from the
first iterator, and the second element comes from the second iterator.
In other words, it zips two iterators together, into a single one.
If either iterator returns None
, next
from the zipped iterator
will return None
.
If the zipped iterator has no more elements to return then each further attempt to advance
it will first try to advance the first iterator at most one time and if it still yielded an
item try to advance the second iterator at most one time.
zip()
uses IntoIterator
, we can pass
anything that can be converted into an Iterator
, not just an
Iterator
itself. For example:
collect()
can take anything iterable, and turn it into a relevant
collection. This is one of the more powerful methods in the core
library, used in a variety of contexts.
The most basic pattern in which collect()
is used is to turn one
collection into another. You take a collection, call iter
on it,
do a bunch of transformations, and then collect()
at the end.
collect()
can also create instances of types that are not typical
collections.
Because collect()
is so general, it can cause problems with type
inference. As such, collect()
is one of the few times you’ll see
the syntax affectionately known as the ‘turbofish’: ::<>
. This
helps the inference algorithm understand specifically which collection
you’re trying to collect into.
: Array
on the left-hand side.
Using the ‘turbofish’ instead of annotating doubled
:
collect()
only cares about what you’re collecting into, you can
still use a partial type hint, _
, with the turbofish:
peek
method to look at the next element of the
iterator. See its documentation for more information.
Note that the underlying iterator is still advanced when peek
is called for the first
time: In order to retrieve the next element, next
is called on the underlying iterator,
hence any side effects (i.e. anything other than fetching the next value) of the next
method will occur.
n
elements, or fewer
if the underlying iterator ends sooner.
take(n)
yields elements until n
elements are yielded or the end of
the iterator is reached (whichever happens first).
The returned iterator is a prefix of length n
if the original iterator
contains at least n
elements, otherwise it contains all of the
(fewer than n
) elements of the original iterator.
n
elements are available,
take
will limit itself to the size of the underlying iterator:
sum()
can be used to sum any type implementing [Sum
][core::iter::Sum
],
including [Option
][Option::sum
] and [Result
][Result::sum
].
sum()
and a primitive integer type is being returned, this
method will panic if the computation overflows.
product()
and a primitive integer type is being returned, this
method will panic if the computation overflows.
chain()
will return a new iterator which will first iterate over
values from the first iterator and then over values from the second
iterator.
In other words, it links two iterators together, in a chain. 🔗
Arguments do not have to be of the same type as long as the underlying iterated
over items are.
chain()
uses IntoIterator
, we can pass
anything that can be converted into an Iterator
, not just an
Iterator
itself. For example, arrays implement
IntoIterator
, and so can be passed to chain()
directly: