是否有内置方法来检查#next或#peek是否会引发StopIteration?

时间:2019-09-16 20:08:11

标签: ruby enumerator

我正在与一些迭代器一起工作,在这些迭代器中,我必须按照以下原则进行操作(enum是枚举器)

enums_with_zero << enum.rewind if enum.peek == 0

通常可以正常工作,但这是在枚举上已经多次调用#next之后。问题是enum可能在最后,并且为enum传递了一些值,我遇到了enum.peek引发StopIteration的问题,因为{ {1}}完成。有没有一种方法可以让我看管enumenum.peek导致enum.next的原因,然后再调用它。像这样的行为?

StopIteration

1 个答案:

答案 0 :(得分:5)

您可以显式地rescue StopIteration,但是也有一种想法,loop方法通过简单地退出循环来在内部挽救StopIteration异常。 (在loop内部,raise StopIterationbreak具有相同的作用。)

当您尝试窥视结尾时,此代码仅退出循环:

a = %w(a b c d e).to_enum

loop do
  print a.peek
  a.next
end

代码输出abcde。 (它也透明地举起和营救StopIteration。)

因此,如果您想窥视结尾时只想忽略StopIteration异常,只需使用loop

当然,一旦您窥视了结尾,您将被甩出循环。如果您不希望这样做,可以使用whilerescue自定义行为。例如,如果要避免越过终点而退出,而在使用next越过终点而退出时,可以执行以下操作:

a = %w(a b c d e).to_enum

while true
  begin  
    print a.peek
  rescue StopIteration
    print "\nTried to peek past the end of the enum.\nWe're gonna overlook that.\n"
  end
  x = a.next rescue $!
  break if x.class == StopIteration
end

p 'All done!'

循环的最后两行与此具有相同的作用,您可以改用它:

begin
  a.next
rescue StopIteration
  break
end

需要说明的一点是,处理StopIteration是Ruby处理迭代器末尾的预期方式。引自Matz的书 Ruby编程语言

  

外部迭代器的使用非常简单:每次需要另一个时,只需调用next   元件。如果没有其他元素,next将引发StopIteration异常。   这似乎很不正常-预期终止会引发异常   状况,而不是意料之外的异常事件。 (StopIteration是后代   StandardErrorIndexError中;请注意,这是唯一的例外之一   名称中没有单词“ error”的类。)Ruby在此遵循Python   外部迭代技术。通过将循环终止视为异常,   您的循环逻辑非常简单;无需检查的返回值   next获得特殊的迭代结束值,则无需调用某种   next?谓词,然后再调用next