首先看看一下闭合函数(closure),见如下代码:
function newCounter()
local i = 0 -- 非局部变量(non-local variable)
return function () -- 闭合函数(closure)
i = i +
return i
end
end c1 = newCounter()
print(c1()) --
print(c1()) -- c2 = newCounter()
print(c2()) --
print(c1()) --
print(c2()) --
闭合函数可以用来实现迭代器(iterator)(迭代器用来遍历集合,每调用一次函数,即返回集合中的下一个元素)。
例如:遍历一个table的时候,我们经常使用如下方式。
t = {'x', 'y', 'z'}
for k, v in ipairs(t) do
print(k .. " " .. v)
end
-- 打印结果
-- 1 x
-- 2 y
-- 3 z
我们可以用while遍历集合,也可以用for,并且用for会容易很多,下面看一下for的语义:
-- A for statement like for var_1, ···, var_n in explist do block end
-- is equivalent to the code: do
local f, s, var = explist
while true do
local var_1, ···, var_n = f(s, var)
var = var_1
if var == nil then break end
block
end
end
-- Note the following: -- explist is evaluated only once. Its results are an iterator function, a state, and an initial value for the first iterator variable.
-- f, s, and var are invisible variables. The names are here for explanatory purposes only.
-- You can use break to exit a for loop.
-- The loop variables var_i are local to the loop; you cannot use their values after the for ends. If you need these values, then assign them to other variables before breaking or exiting the loop.
注:
1 for做的第一件事就是对in后面的表达式求值,这些表达式应该返回3个值供for保存:迭代器函数(f)、恒定状态(s)、控制变量的初值(var),不足的值用nil补足。
2 在初始化之后,for会以恒定状态s和控制变量var来调用迭代函数f,然后for将迭代起的返回值赋予变量列表中的变量(var_1, var_2 ..., var_n),其中var_1称为控制变量,当返回的var_1为nil时,循环终止。
下面是书中的Lua实现ipair的例子:
t3 = {"x", "y", "z"} local function iter (a, i)
i = i +
local v = a[i]
if v then
return i, v -- 第一个返回值是控制变量
end
end function __ipairs (a)
return iter, a, 0 -- 3个值,迭代器、恒定状态、控制变量。 第一次是iter(a, 0),之后则是iter(a, i)
end for i, v in __ipairs(t3) do
print(i .. " " .. v)
end -- 输出结果:
-- 1 x
-- 2 y
-- 3 z
结合上面for的语义表达式,来分析上面这段代码,__ipairs是一个工厂,生产迭代器iter,迭代器的初始参数是a和0,即恒定状态(a)和控制变量(i),iter的返回值是控制变量i和返回值a[i]。
pairs与ipairs类似,但key是无序的,它的迭代器函数是 Lua中的一个基本函数next,在调用next(t, k)时,k是table t的一个key,此调用会以table中的任意次序返回一组值,而调用next(t, nil)时,返回table的第一组值。若没有下一组值的时候,next返回nil。
function pairs(t)
return next, t, nil
end
也可以直接使用next:
for k, v in next, t do
<loop body>
end