Lua 迭代器

一、迭代器如何运转

迭代器是一种可以遍历一个集合中所有元素的代码结构。

在 Lua 中,迭代器会结合着 for 语法来进行,运行的模式如下图所示

结合代码结构,可以这么理解

lua 复制代码
for var_1, var_2, var_3, ... var_n in exp_list do 
    block 
end

等价于

lua 复制代码
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 )从而达到迭代完成。

lua 复制代码
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 的数组较为常用,可以自行实现一个类似的迭代器,只需实现一个真正遍历的函数即可

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) 判断其返回值。

lua 复制代码
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 函数,然后通过上一次的索引推导下一次的值即可

lua 复制代码
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吧,码字不易,请多多支持)

如果觉得本篇博文对你有所启发或是解决了困惑,点个赞或关注我呀

公众号搜索 "江澎涌",更多优质文章会第一时间分享与你。

相关推荐
鹿鹿学长6 小时前
2025年全国大学生数学建模竞赛(C题) 建模解析|婴儿染色体数学建模|小鹿学长带队指引全代码文章与思路
c语言·开发语言·数学建模
伴杯猫6 小时前
【ESP32-IDF】基础外设开发2:系统中断矩阵
c语言·单片机·嵌入式硬件·mcu·物联网·github
利刃大大7 小时前
【高并发内存池】五、页缓存的设计
c++·缓存·项目·内存池
C语言小火车7 小时前
【C++八股文】基础知识篇
c++·tcp/ip·const·智能指针·多线程同步·static关键字·c++内存模型
liulilittle7 小时前
IP校验和算法:从网络协议到SIMD深度优化
网络·c++·网络协议·tcp/ip·算法·ip·通信
眠りたいです8 小时前
基于脚手架微服务的视频点播系统-播放控制部分
c++·qt·ui·微服务·云原生·架构·播放器
Want5958 小时前
C/C++圣诞树①
c语言·开发语言·c++
老赵的博客8 小时前
c++ 杂记
开发语言·c++
jimmy.hua8 小时前
[C++刷怪笼]:set/map--优质且易操作的容器
开发语言·c++
tan180°9 小时前
Boost搜索引擎 网络库与前端(4)
linux·网络·c++·搜索引擎