This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
The third edition targets Lua 5.2 and is available at Amazon and other bookstores.
By buying the book, you also help to support the Lua project.
|Programming in Lua|
|Part I. The Language Chapter 7. Iterators and the Generic for|
The name "iterator" is a little misleading, because our iterators do not iterate: What iterates is the for loop. Iterators only provide the successive values for the iteration. Maybe a better name would be "generator", but "iterator" is already well established in other languages, such as Java.
However, there is another way to build iterators wherein iterators actually do the iteration. When we use such iterators we do not write a loop; instead, we simply call the iterator with an argument that describes what the iterator must do at each iteration. More specifically, the iterator receives as argument a function that it calls inside its loop.
As a concrete example,
let us rewrite once more the
allwords iterator using this style:
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 endTo use such iterator, we must supply the loop body as a function. If we only want to print each word, we simply use
allwords(print)More often, we use an anonymous function as the body. For instance, the next code fragment counts how many times the word "hello" appears in the input file:
local count = 0 allwords(function (w) if w == "hello" then count = count + 1 end end) print(count)The same task, written with the previous iterator style, is not very different:
local count = 0 for w in allwords() do if w == "hello" then count = count + 1 end end print(count)
True iterators were popular in older versions of Lua, when the language did not have the for statement. How do they compare with generator-style iterators? Both styles have approximately the same overhead: one function call per iteration. On the one hand, it is easier to write the iterator with this second style (although we can recover this easiness with coroutines). On the other hand, the generator style is more flexible. First, it allows two or more parallel iterations. (For instance, consider the problem of iterating over two files comparing them word by word.) Second, it allows the use of break and return inside the iterator body. (With a true iterator, a return returns from the anonymous function, not from the function doing the iteration.)
|Copyright © 2003–2004 Roberto Ierusalimschy. All rights reserved.|