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

Eli*_*off 3 ruby enumerator

我正在与几个迭代器一起工作,在这些迭代器中,我必须按照以下方式做点事情(enum是一个枚举器)

enums_with_zero << enum.rewind if enum.peek == 0
Run Code Online (Sandbox Code Playgroud)

通常可以正常工作,但这是在#next枚举已经被调用几次之后。问题在于,enum可能在末尾传递了一些值enum,我遇到enum.peekStopIteration因为enum完成而引发问题的问题。有没有一种方法我可以把在保护检查enum.peekenum.next会导致StopIteration之前,我把它。例如,某些东西会具有这种行为?

class Enumerator
  def has_next?
    begin
      peek && true
    rescue StopIteration
      false
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

Bob*_*des 5

你可以rescueStopIteration明确的,但也有该想法loop方法在内部抢救一个StopIteration通过简单地退出循环异常。(内部loopraise StopIteration具有相同的效果break)。

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

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

loop do
  print a.peek
  a.next
end
Run Code Online (Sandbox Code Playgroud)

代码输出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!'
Run Code Online (Sandbox Code Playgroud)

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

begin
  a.next
rescue StopIteration
  break
end
Run Code Online (Sandbox Code Playgroud)

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

外部迭代器的使用非常简单:next每次需要另一个元素时都调用它。当没有剩余的元素时,next将引发StopIteration异常。这似乎很不寻常-预期的终止条件会引发异常,而不是意外的异常事件。(StopIteration是的后裔StandardErrorIndexError;请注意,它是没有在其名称中的“错误”,唯一的例外类之一。)红宝石遵循的Python在这种外部迭代技术。通过将循环终止视为一个例外,它使循环逻辑变得非常简单。无需检查返回值是否 next为特殊的迭代结束值,也无需在调用next?之前调用某种 谓词next