泛型for迭代器
泛型for迭代器会在自己内部保存迭代函数,它会保存三个值:迭代函数、状态常量、控制变量。
Lua中默认的迭代函数为ipairs
下面我们看看范性for的执行过程:
- 首先,初始化,计算in后面表达式的值,表达式应该返回范性for需要的三个值:迭代函数、状态常量、控制变量;与多值赋值一样,如果表达式返回的结果个数不足三个会自动用nil补足,多出部分会被忽略。
- 第二,将状态常量和控制变量作为参数调用迭代函数(注意:对于for结构来说,状态常量没有用处,仅仅在初始化时获取他的值并传递给迭代函数)。
- 第三,将迭代函数返回的值赋给变量列表。
- 第四,如果返回的第一个值为nil循环结束,否则执行循环体。
- 第五,回到第二步再次调用迭代函数
在Lua中我们常常使用函数来描述迭代器,每次调用该函数就返回集合的下一个元素。Lua 的迭代器包含以下两种类型:
- 无状态的迭代器
- 多状态的迭代器
无状态迭代器
无状态的迭代器是指不保留任何状态的迭代器,因此在循环中我们可以利用无状态迭代器避免创建闭包花费额外的代价。
每一次迭代,迭代函数都是用两个变量(状态常量和控制变量)的值作为参数被调用,一个无状态的迭代器只利用这两个值可以获取下一个元素。
重写ipairs,为其命名为ipairs2
function ipairs2(a)
return iter, a, 0
end
function iter(a, i)
i = i + 1
local v = a[i]
if(v) then
return i, v
else
return nil, nil
end
end
local array = {"one", "two", "three"}
for k, v in ipairs2(array) do
print(k .. ":" .. v)
end
--输出
--1:one
--2:two
--3:three
以上的程序也等同于以下
function iter(a, i)
i = i + 1
local v = a[i]
if(v) then
return i, v
else
return nil, nil
end
end
local array = {"one", "two", "three"}
for k, v in iter, array, 0 do
print(k .. ":" .. v)
end
不适用ipairs2,而是直接在for循环中初始化。
拓展,适用while循环实现迭代效果
function ipairs2(a)
print("ipairs2只调用一次")
return iter, a, 0
end
function iter(a, i)
i = i + 1
local v = a[i]
if(v) then
return i, v
else
return nil, nil
end
end
local array = {"one", "two", "three"}
local _it, _s, _var = ipairs2(array)
while true do
local var_1, var_2 = _it(_s, _var)
_var = var_1
if _var == nil then
break
end
print(var_1 .. ":" .. var_2)
end
多状态迭代器
很多情况下,迭代器需要保存多个状态信息而不是简单的状态常量和控制变量,最简单的方法是使用闭包,还有一种方法就是将所有的状态信息封装到table内,将table作为迭代器的状态常量,因为这种情况下可以将所有的信息存放在table内,所以迭代函数通常不需要第二个参数。
function ipairs2(a)
local index = 0
local count = #a
return function()
index = index + 1
if index <= count then
return index, a[index]
end
end
end
local array = {"one", "two", "three"}
for k, v in ipairs2(array) do
print(k .. ":" .. v)
end
多状态迭代器主要是通过自己内部的变量来控制直接的迭代。