【问题标题】:"break" vs "raise StopIteration" in a Ruby EnumeratorRuby 枚举器中的“break”与“raise StopIteration”
【发布时间】:2016-12-15 20:44:52
【问题描述】:

如果我使用 Ruby Enumerators 来实现生成器和过滤器:

generator = Enumerator.new do |y|
  x = 0
  loop do
    y << x
    x += 1
    break if x > CUTOFF
  end
end.lazy

filter = Enumerator.new do |y|
  loop do
    i = generator.next
    y << i if i.even?
  end
end

我是否使用打破生成器的循环有什么区别

break if x > CUTOFF

raise StopIteration if x > CUTOFF

?

两者似乎都有效。我想break 会更高效,但raise 在这里更惯用吗?

【问题讨论】:

  • 因为您正在使用lazy,所以我个人会选择raise StopIteration
  • 这似乎是一种使用 ruby​​ 的非常 Python 的方式。根据您要完成的工作,可能有更好的方法来实现它
  • @Zack 该示例并不能很好地代表我的真实用例——只是一个过于简单的示例来演示我遇到的问题。真正的生成器进行一系列 api 调用,分批获取记录,每次生成一条记录,直到需要获取另一批记录。这一切都包含在另一个 Enumerator 中,该 Enumerator 过滤掉与调用代码相关的记录。

标签: ruby enumerator


【解决方案1】:

在 Ruby 中,considered a bad practice 使用 raise/fail 进行控制流,因为它们真的很慢。

所以回答你的问题raise StopIteration if x &gt; CUTOFF 不是打破循环的惯用方式

【讨论】:

  • Tisk*Tisk 因为这正是Enumerator#next 处理退出循环的方式。 (以及#peek#next_values。老实说,我总是将raise StopIteration 用于Kernel#loopEnumerator,因为显然ruby 团队不仅支持这个概念,而且个人也依赖它
  • @engineersmnky 不幸的是,rails 和 ruby​​ 的旧部分由今天不被认为是惯用的代码组成。 Mike Perham (sidekiq 的创建者) 写了a great post 关于它
  • 使用大多数“关键字”一般来说不是惯用的(break 是关键字)。我的建议是LazyEnumerator 可能会有更好的实现。我认为,如果核心团队想要修复 StopIteration 的使用,鉴于其范围有限,它会很简单
  • 有趣的是从来没有想过使用关键字不是惯用的。这是一种基本的语言语法,使用它没有任何问题。虽然我同意完全有更好的实现
  • 考虑到这一点,我倾向于在这样的简单情况下使用简单的break,并在循环内的嵌套方法调用需要时使用StopIteration或者这样做会显着提高代码的清晰度。
猜你喜欢
  • 2012-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-07
  • 2012-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多