rubyloopsenumerators

Graceful way of stopping at the end of an enumerator?


Is there a graceful way of realizing one is at the end of an enumerator?

For instance,

a = (1..10).to_a
e = a.each
e.next # should yield 1
while e.next
  # do something
end

Of course, e raises StopIteration when you get to the end of the enumerator.

Is there a nice way of breaking out of that while loop without a rescue? I know that I can just say e.each (or just not use the enumerator at all), but for my specific problem I want to do something special for the first few iterations and then something general for the last few.

I want a way of looking at the next value and getting nil instead of an error.

Any tips? There's probably something obvious that I'm missing...

NB. I don't have to use enumerators, but it seems like the easiest way to solve my problem. So if you have a non enumerator solution (for iterating through an enumerable), feel free to share. (on that note, maybe I should just use each or each_with_index and use the counter for the special cases...)


Solution

  • Rescuing from StopIteration is the way to do it. And the only way.*

    When you realize that any value (e.g. nil, as you suggest) returned by next could be the next value of the enumerable, it becomes clear that it's not possible for it to return a special-case value, since that could then never be in the enumerable. This is why next must raise StopIteration when complete instead of doing something more "graceful".

    *Assuming you must use Enumerator, as there's probably a better way to solve your real problem without doing so.