所谓迭代器就是一种可以遍历一种集合中所有元素的机制。
每个迭代器都需要在每次成功调用之间保存一些状态,这样才知道下一步进行到何处,而Closure
则为这一任务提供了很好的支持。
function value (t)
local i = 0
return function ()
i = i + 1; return t[i]
end
end
value()在调用时会创建一个Closure
,其中的i保存着迭代的索引值,每调用一次会加一
,直到最后一个元素,之后将会返回nil
t = {20, 30, 40}
for element in value(t) do
print(element)
end
泛型for
在循环过程内部保存了迭代器函数。实际上保存着3个值:
泛型for的语法:
for in <exp-list> do
end
是一个或多个变量名的列表,以逗号分隔开
是一个或多个表达式的列表,以逗号分隔开
变量列表的第一个元素称为“控制变量”。循环过程中决不会为nil,因为当其为nil时循环就已经结束了。for做的第一件事情就是对in后面的表达式进行取值,将会返回3个值给for保存。初始化步骤后,for会以恒定状态和控制变量来调用迭代器函数。然后for将迭代器函数返回值赋予变量列表中的变量。若第一个返回值为空则停止循环。
一种不保存任何状态的迭代器 (可以在多个循环中使用他而不会有新的Closure开销
这样迭代器的典型例子就是ipairs
a = {"one", "two", "three"}
for i,v in ipairs(a) do
print(i, v)
end
下面是ipairs的实现
local function iter (a, i)
i = i + 1
local v = a[i]
if v then
return i,v
end
function ipairs (a)
return iter, a, 0
end
当Lua调用for循环中的ipairs(a)时,他将获得迭代函数,恒定状态a,控制变量的初始值0。Lua调用iter(a,0),得到1,a[1] 继续调用iter(a,2),获得2,a[2]
pairs
与ipairs
的区别
pairs的迭代器函数是Lua中的一个基本函数next
迭代器需要保存许多状态,使用Closoure可以将需要的状态保存在恒定状态中
范例代码:
local iterator
function allwords()
local state = {line = io.read, pos = 1}
return iterator, state
end
function iterator (state)
while state.line do --若为有效行的执行内容就进入循环
--搜索下一个单词
local s,e = string.find(state.line, "%w+", state.pos)
if s then --找到了一个单词
--更新下一个位置
state.pos = e + 1
return string.sub(state.line, s, e)
else --没有找到单词
state.line = io.read() --读取下一行
state.pos = 1 --从第一个位置开始
end
end
return nil
end
真正的迭代器
迭代器并没有做实际的迭代,真正做迭代的是for循环。而迭代器只是每次迭代提供一些成功后的返回值。还有一种创建迭代器的方式:在迭代器中做实际的迭代操作
可以重写allwords()
函数
function allwords (f)
for line in io.lines() do
for word in string.gmatch(line, "%w+") do
f(word)
end
end
end
使用这个迭代器时,需要传入一个描述循环体的函数。如果要打印每个单词,那么可以使用print: allwords(print)