【问题标题】:Fooling with the for iterator愚弄 for 迭代器
【发布时间】:2014-09-30 07:42:16
【问题描述】:

以下代码来自我查看过的程序。它计算第n个斐波那契数:

for i in 2..input.to_i
  fibonacci = a + b
  a = b
  b = fibonacci
  i += 1            # <-  This
end

注释行 i += 1 实际上什么都不做。

i是块参数对吗? IE。 for 语句在功能上是否与 (2..input.to_i).each do |i| 相同?

i += 1 行实际上并不影响迭代器。迭代器是否可以使用foreachtimes 循环移动到某个迭代?

也欢迎提及这些迭代器的工作方式。

【问题讨论】:

    标签: ruby loops iterator


    【解决方案1】:

    首先,这是您想要的参考资料:

    回答您的问题:

    1. 说i是块参数对吗?

      没有。 for 没有引入新的变量作用域或使用块。

    2. for 语句在功能上是否与 (2..input.to_i).each do |i| 相同?

      没有。 for i in ... 在执行 for 的范围内创建一个变量 i,而 each 不会这样做(IIRC 早期的 Ruby 版本会这样做)。

    3. 迭代器是否可以移动到某个迭代?

      您可以像这样跳过或重做单次迭代(each 迭代中也可能):

      wait_until = Time.now + 10
      for i in [1,2,3]
        redo if Time.now < wait_until # actively sleep
        next if i.even?
      end
      

      但你不能跳到任意位置。

      为了更好地控制迭代,您需要一个 Enumerator 实例。如果你在没有参数/块的情况下调用each,你会得到一个枚举器:

      enum = [1,2,3].each
      begin
        while i = enum.next
          puts i
        end
      rescue StopIteration
      end
      
      # equivalent to
      # [1,2,3].each {|i| puts i }
      

      enum 现在会响应 rewindpeek 等内容(请参阅上面链接的文档)。

    【讨论】:

    • 我认为你的第二点有点误导。是的,严格来说并不完全一样,因为变量作用域不同。但是,ISO Ruby 语言规范的第 11.5.2.3.4 节指出,for var1, var2 in expression; do_something end确实评估为 expression.each do |var1, var2| do_something end,只是该块没有自己的范围。所以,范围是唯一的区别,否则它实际上只是each的纯本地句法翻译(即句法糖)。
    • 你说的很对,等我有空的时候再说一遍……
    【解决方案2】:

    for 实际上大部分只是each 的糖(尝试在不可枚举的对象上使用for - 它应该抱怨它没有响应每个对象)。它的不同之处在于它不创建块范围。

    each 的实现方式取决于您调用它的对象(每个对象都是构建所有 Enumerable 的方法)。在任何情况下,都会使用一系列值调用该块。重新分配产生的块变量没有任何作用 - 在下一次迭代时,i 被设置为下一个值应该是什么。

    您可以使用next 跳过或使用break 终止,但这就是控制迭代的方式 - 没有办法说“向前跳转 3”

    【讨论】:

      猜你喜欢
      • 2014-01-22
      • 2014-04-11
      • 1970-01-01
      • 1970-01-01
      • 2015-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多