第 7 章。这一章看得不是很明白。
迭代器可以遍历一个集合中的所有元素。在 lua 中,迭代器一般都是函数,每次调用这个函数都会返回集合中的“下一个”元素,前面提到的闭包函数就是实现迭代器的很好选择:
function values (t)
local i = 0
return function ()
i = i + 1
return t[i]
end
end
arr = {"one", "two", "three"}
iter = values(arr)
while true do
local e = iter()
if e == nil then
break
end
print(e)
end
函数 values() 返回一个匿名函数,每次调用这个匿名函数都会返回传给 values() 的“下一个”值。更常见的情况是写成“for ... in ...”的形式:
function values (t)
local i = 0
return function ()
i = i + 1
return t[i]
end
end
arr = {"one", "two", "three"}
for it in values(arr) do
print(it)
end
for 语句保存了 values()
返回的匿名函数,并且把每次调用匿名函数返回的值保存在变量 it 中,直到 it 为 nil 为止。在这里 for 循环保存了三个隐含变量:匿名函数,不变量(在循环中不会改变)和控制变量。一般来说,for 循环的形式是:
for <var-list> in <exp-list> do
<body>
end
这里 var-list 和 exp-list 都是用逗号分隔的变量。
for 语句做的第一件事是计算“in”后表达式的值,然后把不变量和控制变量传递给匿名函数作为参数调用匿名函数,把返回值依次赋给 var-list 中的变量。接着判断 var-list 中第一个变量是否为空,不为空的话继续执行 for 中的 body 部分。例如语句:
for var_1, var_2, ..., var_n in <exp-list> do <block> end
等价于下面的形式:
do
local func, invariant, var = <exp-list>
while true do
local var_1, var_2, ..., var_n = func(invariant, var)
var = var_1
if var == nil then
break
end
<block>
end
end
因此前面的 values() 函数等价于:
function values (t)
local i = 0
return function ()
i = i + 1
return t[i]
end
end
arr = {"one", "two", "three"}
do
local func, invariant, var = values(arr), arr
while true do
local it = func(invariant, var)
var = it
if var == nil then
break
end
print(it)
end
end
另外有一种是无状态的迭代器,它不会保存任何状态。每次循环调用迭代函数并且把不变量和控制变量传递给它,然后获取迭代函数的返回值。一个无状态迭代器的例子就是 ipairs():
a = {"one", "two", "three"}
for i, v in ipairs(a) do
print(i, v)
end
使用迭代器实现:
function iter(a, i)
i = i + 1
if a[i] then
return i, a[i]
end
end
function ipairs(a)
return iter, a, 0
end
arr = {"one", "two", "three"}
for i, v in ipairs(arr) do
print(i, v)
end
在一个迭代器中经常要保存很多状态,最简单的做法是使用闭包,另一种做法是把要保存的内容都放到一个 table 中,并且可以改变 table 中元素的值。
上面使用的术语“迭代器”(iterator)有歧义,其实叫“生成器”(generator)更合适,因为每次调用它只是返回“下一个”值。另一种创建迭代器的方法就是写一个接收一个函数作为参数(也就是所谓的回调函数)的函数,在主函数中有一个循环,每次循环都调用这个回调函数。举个例子:
function real_iter(f)
local i = 0
while i < 5 do
f(i)
i = i + 1
end
end
real_iter(print)
print("--------------------")
function func5(v)
print(v + 5)
end
real_iter(func5)
函数 real_iter() 从 0 到 4,每次把当前的值传给回调函数 f。第 9 行 print() 作为参数,依次打印 i 的值;第 17 行 func5() 作为参数,打印 (i+5) 的值。