Are side-effects of the closure in `Iterator::inspect` well defined so it can be used for e.g. counting?

Viewed 283

I have an iterator and I would like to fold it with a nice method (say Iterator::sum):

let it = ...;
let sum = it.sum::<u64>();

Then I notice that I also need to know the number of elements in the iterator. I could write a for loop and do the counting and summing up manually, but that's not nice since I have to change a potentially long iterator adapter chain and all of that. Additionally, in my real code I'm not using sum, but a more complex "folding method" which logic I don't want to replicate.

I had the idea to (ab)use Iterator::inspect:

let it = ...;
let mut count = 0;
let sum = it.inspect(|_| count += 1).sum::<u64>();

This works, but does it work by coincidence or is this behavior guaranteed? The documentation of inspect mentions that the closure is called for each element, but also states that it's mostly used as debugging tool. I'm not sure if using it this way in production code is a good idea.

1 Answers

I'd say it's guaranteed, but you'll never find it explicitly stated as such. As you mention, the documentation states:

Do something with each element of an iterator, passing the value on.

Since the function guarantees to run the closure for each element, and the language guarantees what happens when a closure is run (by definition of a closure), the behavior is safe to rely on.

That being said, once you have one or more side-effects, it might be better to eschew heavy chaining and move to a boring for loop for readability, but that will depend on the exact case.

Related