▒ 目录 ▒
🛫 导读
需求
本教程面向 Lua 初学者及需要深化 table 应用的开发者,核心解决以下需求:
- 理解 table 作为 Lua 唯一数据结构的本质特性,
- 掌握 table 的创建、增删改查等基础操作,
- 攻克遍历、排序、嵌套等进阶场景,最终能灵活运用 table 实现数组、字典、结构化数据存储(如游戏角色属性、用户信息表)等实际开发需求,规避使用中的常见问题(如索引混乱、长度计算误差)。
开发环境
版本号 | 描述 | |
---|---|---|
文章日期 | 2025-08-30 | |
IDE | https://www.mycompiler.io/new/lua | 5.3 |
1️⃣ table核心认知:Lua的“万能数据容器”
table是Lua语言的基石数据结构,无固定类型限制,可同时存储数值、字符串、函数甚至其他table,本质是“键值对(key-value)集合”。
其独特性在于:既支持“数值键”(模拟数组,索引从1开始),也支持“自定义键”(模拟字典),且两种模式可混合使用,满足多样化数据组织需求。
table的两种核心模式
- 数组模式:键为连续整数(默认从1开始),适合存储有序列表(如商品列表、分数排名),示例:
-- 数组模式:存储3个学生姓名,键自动为1、2、3 studentNames = {"张三", "李四", "王五"} print(studentNames[1]) -- 输出:张三(注意:非0开始) print(studentNames[3]) -- 输出:王五
- 字典模式:键为自定义字符串/数值(非连续),适合存储关联数据(如用户属性、配置信息),示例:
-- 字典模式:存储用户信息,键为自定义字符串 userInfo = {name = "赵六", age = 25, isVip = true} print(userInfo.age) -- 输出:25(语法糖写法) print(userInfo["isVip"]) -- 输出:true(标准写法)
table的创建方式
Lua提供两种创建table的方式,根据数据确定性选择:
- 空table初始化:先创建空容器,后续动态添加数据,适合数据未知场景:
-- 步骤1:创建空table shoppingCart = {} -- 步骤2:动态添加数据(数组模式+字典模式) shoppingCart[1] = "牛奶" -- 数组模式:键1 shoppingCart[2] = "面包" -- 数组模式:键2 shoppingCart.count = 2 -- 字典模式:键count print(#shoppingCart) -- 输出2,只计算从1开始的连续数组长度
- 直接赋值初始化:创建时直接定义所有键值对,适合数据已知场景,示例:
-- 直接初始化:混合存储书籍信息 book = { "Lua程序设计", "Python入门", -- 数组:键1-2(书籍名称) author = "Lua团队", -- 字典:键author(作者) price = 59.9 -- 字典:键price(价格) } print(#shoppingCart) -- 输出2,只计算从1开始的连续数组
2️⃣ table基础操作:增删改查与长度计算
掌握“增、删、改、查”是table使用的核心,而长度计算是衡量table规模的基础操作,需理解
#
运算符的适用范围与限制。
新增数据(增)
数组模式新增:
直接赋值:通过“最大索引+1”添加,适合有序扩展:
fruits = {"苹果", "香蕉"} fruits[3] = "橙子" -- 最大索引为2,新增索引3 print(fruits[3]) -- 输出:橙子
内置函数
table.insert(t, pos, value)
:指定位置插入(pos可选,默认末尾),示例:table.insert(fruits, "葡萄") -- 末尾插入,数组变为{"苹果","香蕉","橙子","葡萄"} table.insert(fruits, 2, "草莓")-- 索引2插入,数组变为{"苹果","草莓","香蕉","橙子","葡萄"}
字典模式新增:直接通过“键=值”赋值,不存在的键会自动创建:
function printT(t) for i, v in pairs(t) do print(i, v) end end phone = {brand = "华为", model = "Mate 60"} phone.color = "黑色" -- 新增键color phone["storage"] = "512G" -- 新增键storage -- print(phone.color, phone.storage) -- 输出:黑色 512G printT(phone)
删除数据(删)
数组模式删除:使用
table.remove(t, pos)
(pos可选,默认末尾),删除后后续元素自动前移:function printT(t) print('====================') for i, v in pairs(t) do print(i, v) end end fruits = {"苹果","草莓","香蕉","橙子","葡萄"} table.remove(fruits, 2) -- 删除索引2的"草莓",数组变为{"苹果","香蕉","橙子","葡萄"} printT(fruits) table.remove(fruits) -- 删除末尾的"葡萄",数组变为{"苹果","香蕉","橙子"} printT(fruits)
字典模式删除:将键的值设为
nil
(Lua中nil
表示“无值”,等同于删除键值对):function printT(t) print('====================') for i, v in pairs(t) do print(i, v) end end phone = {brand = "华为", model = "Mate 60", color = "黑色"} phone.color = nil -- 删除键color print(phone.color) -- 输出:nil(表示键已不存在) printT(phone)
修改与查询(改、查)
修改数据:对已有键重新赋值,覆盖原有值:
student = {name = "张三", score = 80} student.score = 85 -- 修改score的值为85 student["name"] = "张三丰" -- 修改name的值为"张三丰" print(student.name, student.score) -- 输出:张三丰 85
查询数据:通过“键”获取值,若键不存在则返回
nil
:book = {title = "Lua入门", price = 49.9} print(book.title) -- 输出:Lua入门(字典模式查询) nums = {10, 20, 30} print(nums[2]) -- 输出:20(数组模式查询) print(book.author) -- 输出:nil(键author不存在)
table长度计算(#
运算符)
Lua通过
#
运算符获取table长度,但仅对数组模式(连续整数键) 有效,返回最大连续整数键值,对字典模式或非连续数组不适用:
- 连续数组:
#
返回预期长度:arr = {"a", "b", "c"} print(#arr) -- 输出:3(最大连续键为3)
- 非连续数组:
#
返回第一个nil
前的最大键(结果可能不符合预期):arr = {"a", "b"} arr[4] = "d" -- 键3为nil(不连续) print(#arr) -- 输出:2(因键3为nil,中断连续)
- 混合模式:
#
仅计算数组部分,忽略字典部分:mix = {"a", "b", count = 2} -- 数组键1-2,字典键count print(#mix) -- 输出:2(仅统计数组部分)
- 计算全量长度(含字典):需手动遍历计数:
function getTotalLength(t) local count = 0 for _ in pairs(t) do -- pairs遍历所有键 count = count + 1 end return count end mix = {"a", "b", count = 2} print(getTotalLength(mix)) -- 输出:3(数组2个+字典1个)
3️⃣ table遍历:ipairs
、pairs
与next
函数
遍历是获取table全部数据的核心操作,
ipairs
、pairs
和next
函数各有适用场景,需根据table类型选择。
ipairs
:连续整数键的专属遍历
ipairs(t)
仅遍历从1开始的连续整数键,遇到非整数键或中断的整数键(如键1存在,键2不存在)则停止,适合纯数组:arr = {"a", "b"} arr[4] = "d" -- 键3缺失(中断) arr["key"] = "c" -- 非整数键 for i, v in ipairs(arr) do print(i, v) end -- 输出: -- 1 a -- 2 b -- (键3缺失,键4和"key"被忽略)
pairs
:连续整数键的专属遍历
遍历所有键值对(无论键类型/是否连续),适合混合模式/纯字典模式:
-- pairs遍历:输出所有键值对(键顺序不固定,按Lua哈希表规则) for key, value in pairs(mixTable) do print("键:" .. tostring(key) .. ",值:" .. tostring(value)) end -- 输出(顺序可能不同): -- 键:1,值:a -- 键:2,值:b -- 键:4,值:d -- 键:key,值:c
next
:底层键值对遍历工具
next(t, key)
是Lua底层遍历函数,返回table中“指定key的下一个键值对”,参数key
为nil
时返回第一个键值对,无下一个时返回nil
。可替代pairs
实现灵活遍历:
- 基本用法(模拟
pairs
):t = {a = 1, b = 2, c = 3} local key, value = next(t, nil) -- 从第一个键开始 while key do print(key, value) key, value = next(t, key) -- 获取下一个键值对 end -- 输出(顺序不固定): -- a 1 -- b 2 -- c 3
- 与
ipairs
的差异:next
可遍历所有键(包括非整数、不连续键),ipairs
仅遍历连续整数键:mix = {10, 20, [4] = 40, name = "test"} -- next遍历所有键 key, value = next(mix, nil) while key do print(key, value) key, value = next(mix, key) end -- 输出(含键1、2、4、name)
3️⃣ table排序、嵌套
数组排序:table.sort
的使用
table.sort(t, compare)
用于对数组模式的table排序,compare
为可选比较函数(默认升序):
- 默认升序排序:适用于数值/字符串数组(字符串按ASCII码排序):
-- 数值数组升序 nums = {5, 2, 8, 1} table.sort(nums) print(table.concat(nums, ", ")) -- 输出:1, 2, 5, 8(concat用于拼接数组) -- 字符串数组升序(按ASCII码) words = {"banana", "apple", "cherry"} table.sort(words) print(table.concat(words, ", ")) -- 输出:apple, banana, cherry
- 自定义排序:通过比较函数实现降序或复杂排序(如按table嵌套字段排序):
-- 数值数组降序 nums = {5, 2, 8, 1} table.sort(nums, function(a, b) return a > b -- a > b时交换,实现降序 end) print(table.concat(nums, ", ")) -- 输出:8, 5, 2, 1 -- 嵌套table排序:按学生分数降序 students = { {name = "张三", score = 85}, {name = "李四", score = 92}, {name = "王五", score = 78} } table.sort(students, function(a, b) return a.score > b.score -- 按score字段降序 end) -- 遍历排序结果 for i, stu in ipairs(students) do print(i .. ". " .. stu.name .. ":" .. stu.score) end -- 输出: -- 1. 李四:92 -- 2. 张三:85 -- 3. 王五:78
嵌套table:实现复杂数据结构
嵌套table即“table内存储其他table”,可实现二维数组、树形结构等复杂场景,示例:
- 二维数组(矩阵):存储表格类数据(如成绩表):
-- 二维数组:3行2列(行=学生,列=科目分数) scoreTable = { {math = 90, english = 85}, -- 学生1的分数 {math = 88, english = 92}, -- 学生2的分数 {math = 76, english = 80} -- 学生3的分数 } -- 获取学生2的英语分数 print(scoreTable[2].english) -- 输出:92
- 结构化数据:存储多层关联信息(如游戏角色属性):
-- 嵌套table:游戏角色属性 role = { name = "战士", level = 50, skills = { -- 技能列表(嵌套table) {name = "猛击", damage = 120}, {name = "防御", defense = 80} }, equipment = { -- 装备信息(嵌套table) weapon = "铁剑", armor = "钢甲" } } -- 获取角色第一个技能的伤害 print(role.skills[1].damage) -- 输出:120
🛬 文章小结
- 长度计算:
#
运算符仅适用于连续整数键数组,返回最大连续索引;含字典或非连续键的table需手动遍历计数;- 遍历工具:
ipairs
专注连续整数键(从1开始,中断则停),next
可遍历所有键(底层函数,支持灵活控制遍历过程);- 最佳实践:纯数组用
ipairs
+#
,混合/字典模式用next
(或pairs
)+手动计数,避免依赖#
处理非连续结构。
📖 参考资料
- Lua官方手册:Lua 5.3 Reference Manual