Lua中pairs与ipairs的区别总结
最近在写一个流量转发的东西,用到了 nginx_lua_module 这个模块,需要根据 Header、Body 和 Cookie,按照流量比例把请求转发到其他地方。翻看前人留下的代码,发现循环遍历时,有时候用 pairs,有时候用 ipairs,风格并不统一,读起来让人有点困惑。 好在 Lua 官
最近在写一个流量转发的东西,用到了 nginx_lua_module 这个模块,需要根据 Header、Body 和 Cookie,按照流量比例把请求转发到其他地方。翻看前人留下的代码,发现循环遍历时,有时候用 pairs,有时候用 ipairs,风格并不统一,读起来让人有点困惑。
好在 Lua 官网上有《Programming in Lua》的电子版,专门把这本书翻了一遍,前前后后梳理了一下。下面是这段时间学习 Lua 的几点笔记和思考,不一定全对,但希望能帮到有同样疑问的人。
pairs 与 ipairs 的区别
标准库中提供了几种迭代器:迭代文件每行的 io.lines、迭代 table 元素的 pairs、迭代数组元素的 ipairs、迭代字符串中单词的 string.gmatch 等等。不过这里面的重点,还是 pairs 和 ipairs 这对“孪生兄弟”。

一般的迭代器会在内部维护一个状态——比如当前迭代的位置。但 Lua 的迭代器在设计上是 Stateless(无状态)的,这意味着它可以被重复多次迭代。不像 Python 里,Iterator 和 Iterable 是两个东西,要多次迭代还得从 Iterable 重新拿一个 Iterator。Lua 的迭代器比较简单,状态需要循环自己去维护。
每一次迭代,for 循环都会调用迭代器函数,传入两个参数:一个是无状态的、需要迭代的对象,另一个是控制参数——通常是迭代的当前下标,比如 1、2、3……
举个例子:
a = {"one", "two", "three"}
for i, v in ipairs(a) do
print(i, v)
end
这段代码的执行流程是这样的:ipairs(a) 先执行,返回三个值——迭代函数 iter、迭代对象 a 和迭代起始下标 0。然后第一次 for 循环调用 iter(a, 0),得到当前下标 i 和对应的 a[i] 的值 v,再把这两个值赋给 for 循环定义的 i 和 v。用 Lua 自己写出这个逻辑,大概是这样:
function iter (a, i) i = i + 1 local v = a[i] if v then return i, v end end function ipairs (a) return iter, a, 0 end
那么上面那个 for 循环,等价于下面的调用序列:
iter_function, stateless, index = ipairs(a) iter_function(stateless, index) -- 1 one iter_function(stateless, index+1) -- 2 two iter_function(stateless, index+2) -- 3 three
其中一个需要留意的地方:上面的 Lua 代码中,迭代器函数判断了 v 是否为 nil,只有当 v 不是 nil 时才继续。实际 ipairs 的行为也是如此——一旦遇到 nil,迭代立即停止。比如下面这个 table,因为第二个值是 nil,所以只打印出第一个元素:
a = {"one", nil, "three"}
for i, k in ipairs(a) do
print(i, k)
end
-- 输出只有:1 one
那为什么还需要 pairs 呢?因为 ipairs 是从下标 1 开始顺序取值,抵达第一个 nil 就自动停下。如果 table 中既有数字键又有字符串键,或者数字键之间存在 nil,但你希望遍历出所有元素,ipairs 就不够用了。这时候 pairs 出场。
function pairs (t) return next, t, nil end
for 循环的逻辑和之前一样,pairs 在这里的不同是:它返回的三个元素是 next 函数、迭代对象 a 和起始状态 nil。与 iter 不同,next 返回的是下一个 key-value 对,且其迭代顺序由内部哈希决定(不一定是 1、2、3),直到完全遍历完所有键值对。
看几个例子就更清楚了。
a = {"one", "two", "three"}
for i, v in ipairs(a) do
print(i, v)
end
for i, v in pairs(a) do
print(i, v)
end
输出:
1 one
2 two
3 three
1 one
2 two
3 three
结果一模一样。因为这里的 table 键是连续的整数 1、2、3,不管 ipairs 还是 pairs,效果都一样。
再看一个有字符串键的 table:
t = {
a = "apple",
b = "baby",
c = "cool"
}
for i, v in ipairs(t) do
print(i, v)
end
for k, v in pairs(t) do
print(k, v)
end
结果是:ipairs 什么也不输出(因为 t[1] 是 nil),pairs 则能正常输出所有键值对。
最后一个例子:
local t = {
a=100,10,20,[5]=30
}
for key,value in ipairs(t) do
print(key,value)
--1 10
--2 20
end
for key,value in pairs(t) do
print(key,value)
--1 10
--2 20
--a 100
--5 30
end
结果如注释,不难理解。
总结下来,ipairs 适合用来遍历数组形式的 table(下标连续从 1 开始、无 nil),pairs 则适用于字典形式、键值乱序或含有 nil 的情况。理解了这个区别,代码里该用哪个就很清晰了。
总结
以上就是 Lua 中 pairs 与 ipairs 的核心区别。希望这篇文章对大家的 Lua 学习或实际工作有所帮助。如果有不清楚的地方,欢迎留言交流。
参考资料:
- table 使用手册
- 《Programming in Lua》
Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。
极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。
















