一、迭代器如何运转
迭代器是一种可以遍历一个集合中所有元素的代码结构。
在 Lua 中,迭代器会结合着 for 语法来进行,运行的模式如下图所示
结合代码结构,可以这么理解
for var_1, var_2, var_3, ... var_n in exp_list do
block
end
等价于
do
-- exp_list 可以是一个或多个表达,最后所有的返回值只会使用前三个
local f, s, _var = exp_list
while true do
local var_1, var_2, var_3, ..., var_n = f(s, _var)
_var = var_1
if _var == nil then break end
block
end
end
而这套机制可以结合着闭包,为迭代创建一个 “封闭” 的环境,使用自身迭代所需的变量。
二、如何创建使用迭代器
2-1、闭包工厂
使用闭包工厂,每次都生产一个独立的迭代器。
举个例子:
可以在这个函数内(即 values )保存每次循环的变量,返回的闭包则实现自身所需要的逻辑。
迭代结束,则按照上图所说的返回 nil (第一个返回值,即图中的 var_1 为 nil )从而达到迭代完成。
do
function values(t)
local i = 0
return function(stableValue, var)
print(stableValue, var)
i = i + 1
local v = t[i]
if (v == nil) then
return nil, nil
else
return i, v
end
end, "不可变量", "控制变量"
end
local t = { 10, 20, 30, 40, 50 }
for i, v in values(t) do
print(i, "-----", v)
end
end
--> 不可变量 控制变量
--> 1 ----- 10
--> 不可变量 1
--> 2 ----- 20
--> 不可变量 2
--> 3 ----- 30
--> 不可变量 3
--> 4 ----- 40
--> 不可变量 4
--> 5 ----- 50
--> 不可变量 5
2-2、模仿 ipairs
ipairs 在遍历 Lua 的数组较为常用,可以自行实现一个类似的迭代器,只需实现一个真正遍历的函数即可
local function iter(t, i)
i = i + 1
local v = t[i]
if v then
return i, v
end
end
function my_ipairs(t)
return iter, t, 0
end
print("-----------------------")
print("类似 ipairs:")
-- 效果和 ipairs 一样
local array = { "jiang", "peng", "yong" }
for key, item in my_ipairs(array) do
print(key, "-->", item)
end
--> -----------------------
--> 类似 ipairs:
--> 1 --> jiang
--> 2 --> peng
--> 3 --> yong
print("-----------------------")
print("ipairs:")
for key, item in ipairs(array) do
print(key, "-->", item)
end
--> -----------------------
--> ipairs:
--> 1 --> jiang
--> 2 --> peng
--> 3 --> yong
2-3、模仿 pairs
想要实现一个类似 Lua 的 pairs ,我们需要借助 Lua 内部函数 next
2-3-1、next(table, index)
用于遍历表的所有字段。
参数:
- table:需要被遍历的表
- index:这个表中的一个索引,如果不是 table 中的索引,则会导致异常,默认为 nil(即第一个)。
返回值:
会返回两个值,一个是 key,一个是 value。
在遍历下一个值时,需要使用上一次的索引作为第二个参数,否则迭代不会推进。
当使用最后一个索引或空表时,会返回 nil。
可以使用 next 函数来检测一个表是否为空表,只需要调用 next(table)
判断其返回值。
local l = {
name = "jiang pengyong",
[-100] = 100,
age = 29,
10, 20, 30
}
print(next) --> function: 0x107e6c940
print("判断表是否为空", next({})) --> 判断表是否为空 nil
-- 如果第二个参数不传递,只会返回第一个元素
print("调用两次 nil 的 next:", next(l)) --> 调用两次 nil 的 next: 1 10
print("调用两次 nil 的 next:", next(l)) --> 调用两次 nil 的 next: 1 10
2-3-2、实现类似 pairs 效果
只需要结合 next 函数,然后通过上一次的索引推导下一次的值即可
function my_pairs(t)
return next, t, nil
end
local l = {
name = "jiang pengyong",
[-100] = 100,
age = 29,
10, 20, 30
}
print("---------------------")
print("类似 pairs:")
for key, item in my_pairs(l) do
print(key, "-->", item)
end
--> ---------------------
--> 类似 pairs:
--> 1 --> 10
--> 2 --> 20
--> 3 --> 30
--> -100 --> 100
--> age --> 29
--> name --> jiang pengyong
print("---------------------")
print("pairs:")
for key, item in pairs(l) do
print(key, "-->", item)
end
--> ---------------------
--> pairs:
--> 1 --> 10
--> 2 --> 20
--> 3 --> 30
--> -100 --> 100
--> age --> 29
--> name --> jiang pengyong
三、写在最后
Lua 项目地址:Github传送门 (如果对你有所帮助或喜欢的话,赏个star吧,码字不易,请多多支持)
如果觉得本篇博文对你有所启发或是解决了困惑,点个赞或关注我呀。
公众号搜索 “江澎涌”,更多优质文章会第一时间分享与你。