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
end

12.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