首先看看一下闭合函数(closure),见如下代码:
1 function newCounter() 2 local i = 0 -- 非局部变量(non-local variable) 3 return function () -- 闭合函数(closure) 4 i = i + 1 5 return i 6 end 7 end 8 9 c1 = newCounter() 10 print(c1()) -- 1 11 print(c1()) -- 2 12 13 c2 = newCounter() 14 print(c2()) --1 15 print(c1()) --3 16 print(c2()) --2
闭合函数可以用来实现迭代器(iterator)(迭代器用来遍历集合,每调用一次函数,即返回集合中的下一个元素)。
例如:遍历一个table的时候,我们经常使用如下方式。
1 t = {'x', 'y', 'z'} 2 for k, v in ipairs(t) do 3 print(k .. " " .. v) 4 end 5 -- 打印结果 6 -- 1 x 7 -- 2 y 8 -- 3 z
我们可以用while遍历集合,也可以用for,并且用for会容易很多,下面看一下for的语义:
1 -- A for statement like 2 3 for var_1, ···, var_n in explist do block end 4 -- is equivalent to the code: 5 6 do 7 local f, s, var = explist 8 while true do 9 local var_1, ···, var_n = f(s, var) 10 var = var_1 11 if var == nil then break end 12 block 13 end 14 end 15 -- Note the following: 16 17 -- explist is evaluated only once. Its results are an iterator function, a state, and an initial value for the first iterator variable. 18 -- f, s, and var are invisible variables. The names are here for explanatory purposes only. 19 -- You can use break to exit a for loop. 20 -- 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的例子:
1 t3 = {"x", "y", "z"} 2 3 local function iter (a, i) 4 i = i + 1 5 local v = a[i] 6 if v then 7 return i, v -- 第一个返回值是控制变量 8 end 9 end 10 11 function __ipairs (a) 12 return iter, a, 0 -- 3个值,迭代器、恒定状态、控制变量。 第一次是iter(a, 0),之后则是iter(a, i) 13 end 14 15 for i, v in __ipairs(t3) do 16 print(i .. " " .. v) 17 end 18 19 -- 输出结果: 20 -- 1 x 21 -- 2 y 22 -- 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。
1 function pairs(t) 2 return next, t, nil 3 end
也可以直接使用next:
1 for k, v in next, t do 2 <loop body> 3 end