Description
#780 (comment) by jswrenn
In the Rust standard library, it's quite common for
fold
to be implemented in terms oftry_fold
. In your original code you construct aTakeWhile
and callfold
on it. ButTakeWhile
's fold implementation delegates totry_fold
!The general rule to follow is something like this:
If you need to completely consume an iterator, use
for_each
orfold
.
- Use
for_each
if you don't need to maintain an accumulator.- Use
fold
if you do need to maintain an accumulator.If you need to partly consume an iterator, use
try_for_each
ortry_fold
.
- Same rules about accumulators apply.
Bold is mine as I wonder if we are using for_each
(convenient) at multiple places instead of fold
.
Current for_each
uses:
- lib.rs:
Itertools::{counts, partition_map, join}
- extrema_set.rs:
min_set_impl
- grouping_map.rs:
GroupingMap::{aggregate, collect}
- group_map.rs:
into_group_map
- k_smallest.rs:
k_smallest
(There is also Itertools::foreach
but this one is okay.)
Why do I care? While benchmarking a new MapForGrouping::fold
, I found out that some_slice_iter::for_each
does not delegate to fold
(default behavior) and is not optimized * (just while let Some(x) = self.next() { f(x); }
) while some_slice_iter::fold
is optimized (which is useful to see benchmark improvements of specializing fold
methods of our adaptors by delegating to the inner iterator).
*: The for_each
has a comment: "We override the default implementation, which uses try_fold
, because this simple implementation generates less LLVM IR and is faster to compile."