Iterators and the Generic for
12.1 How the Generic for Works
-- for var1, ..., varN in explist do body end
-- explist evaluates to: iterator function, state, initial control value (and, in 5.4, a closing value)
-- Equivalent to:
do
local f, s, control = explist
while true do
local var1, var2 = f(s, control)
if var1 == nil then break end
control = var1
-- body
end
end12.2 Stateless and Stateful Iterators
pairs(t) respects the __pairs metamethod (5.2+; deprecated in 5.4 but still works). next(t, k) is the primitive behind pairs.
Modifying existing fields (including setting them to nil) during traversal is allowed. Adding new keys during traversal is undefined behavior.
-- Stateless iterator (like ipairs)
local function iter(t, i)
i = i + 1
local v = t[i]
if v ~= nil then return i, v end
end
local function my_ipairs(t) return iter, t, 0 end
for i, v in my_ipairs({"a", "b"}) do print(i, v) end
-- Closure-based (stateful) iterator
local function range(from, to, step)
step = step or 1
local i = from - step
return function()
i = i + step
if (step > 0 and i <= to) or (step < 0 and i >= to) then return i end
end
end
for n in range(1, 10, 3) do print(n) end --> 1 4 7 10
-- Iterate over words in a string
for word in ("the quick brown fox"):gmatch("%a+") do print(word) end
-- Iterate over lines in a file
for line in io.lines("data.txt") do print(line) end
-- Sorted pairs
local function sorted_pairs(t, cmp)
local ks = {}
for k in pairs(t) do ks[#ks + 1] = k end
table.sort(ks, cmp)
local i = 0
return function()
i = i + 1
local k = ks[i]
if k ~= nil then return k, t[k] end
end
end
for k, v in sorted_pairs({c = 3, a = 1, b = 2}) do print(k, v) end
-- Coroutine-based iterators: see Module 24