无状态迭代器,就是一种自身不保存任何状态的迭代器,因此,我们可以在多个循环中使用同一个无状态的迭代器,避免创建新的closure。
在每次迭代中,for循环都会用恒定状态和控制变量来调用迭代器函数。一个无状态的迭代器可以根据这两个值来为下次迭代生成下一个元素。典型例子:ipairs:迭代一个数组的所有元素。
a = {"one", "two", "three"}for i, v in inpairs(a) do print(i, v)end 迭代的状态就是需要遍历的table(一个恒定状态,它不会在循环中改变)及当前的索引值(控制变量)。ipairs(工厂)和迭代器可以在Lua中编写出来。 local function iter (a, i) i = i + 1 local v = a[i] if v then return i, v end end function ipairs(a) return iter, a, 0 end 当Lua调用for循环中的ipairs(a)时,他会获得3个值:迭代器函数iter、恒定状态a和控制变量的初值0.然后Lua调用iter(a,0),得到1和a[1]。在第二次迭代中继续调用iter(a,1),得到2,a[2],一次类推,直至得到第一个nil为止。
函数pairs与ipairs类似,也是用于遍历一个table中的所有元素。不同的是,它的迭代器函数是Lua中的一个基本函数next。
function pairs(t) return next, t, nilend 在调用next(t,k)时,k是table t的一个key。此调用会以table中的任意次序返回一组值:此table的下一个key及这个key所对应的值。而调用next(t, nil)时,返回table的第一组值。若没有下一组值,next返回nil。for k , v in next,t doend
Lua中会自动将for循环中表达式列表的结果调整为3个值。因此,上例中得到了next、t和nil。
关于无状态迭代器的另一个例子(可以遍历列表的迭代器):
local function getnext( list , node) if not node then return list else return node.next endendfunction traverse (list) return getnext, list, nilend 这里将链表的头结点作为恒定状态(traverse返回的第二个值),而将当前节点作为控制变量。第一次调用迭代器函数getnext时,node为nil,因此函数返回list作为第一个结点。在后续调用中node不在为nil,此时迭代器会返回node.next. 对于此迭代器的使用: list = nil for line in io.lines() do list = {val = line, next = list} end for node in traverse(list) do print(node.val) end