珍蜗蜗

不断向前

导航

[Lua] 迭代器 闭合函数 与 泛型for

Posted on 2018-02-28 21:24  珍蜗蜗  阅读(256)  评论(0编辑  收藏  举报

首先看看一下闭合函数(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