第一版是为 Lua 5.0 编写的。虽然在很大程度上仍然适用于后续版本,但有一些差异。
第四版针对 Lua 5.3,可在 Amazon 和其他书店购买。
购买本书,您还可以帮助支持 Lua 项目


7.5 – 真正的迭代器

“迭代器”这个名称有点误导,因为我们的迭代器不会迭代:迭代的是 for 循环。迭代器只为迭代提供连续的值。也许一个更好的名称是“生成器”,但“迭代器”已经在其他语言中得到广泛使用,例如 Java。

然而,还有另一种构建迭代器的方法,其中迭代器实际上执行迭代。当我们使用此类迭代器时,我们不会编写循环;相反,我们只需使用一个参数调用迭代器,该参数描述了迭代器在每次迭代中必须执行的操作。更具体地说,迭代器接收一个函数作为参数,并在其循环中调用该函数。

作为一个具体的示例,让我们使用这种样式再次重写 allwords 迭代器

    function allwords (f)
      -- repeat for each line in the file
      for l in io.lines() do
        -- repeat for each word in the line
        for w in string.gfind(l, "%w+") do
          -- call the function
          f(w)
        end
      end
    end
要使用此类迭代器,我们必须提供循环体作为函数。如果我们只想打印每个单词,我们只需使用 print
    allwords(print)
更常见的是,我们使用匿名函数作为主体。例如,下一个代码片段统计输入文件中单词“hello”出现的次数
    local count = 0
    allwords(function (w)
      if w == "hello" then count = count + 1 end
    end)
    print(count)
使用先前的迭代器样式编写的相同任务并没有太大的不同
    local count = 0
    for w in allwords() do
      if w == "hello" then count = count + 1 end
    end
    print(count)

真正的迭代器在 Lua 的旧版本中很流行,当时该语言没有 for 语句。它们与生成器样式迭代器相比如何?两种样式的开销大致相同:每次迭代一个函数调用。一方面,使用第二种样式编写迭代器更容易(尽管我们可以通过协程恢复这种容易性)。另一方面,生成器样式更灵活。首先,它允许两个或更多并行迭代。(例如,考虑按单词比较两个文件时遇到的迭代问题。)其次,它允许在迭代器主体中使用 breakreturn。(使用真正的迭代器,return 从匿名函数返回,而不是从执行迭代的函数返回。)