Lua表数据类型详解与常见用法介绍
时间:2026-08-21 | 作者:星河游者 | 阅读:0一、简介
表永远是匿名的,表本身和保存表的变量之间没有固定关系。
对于一个表而言,当程序不再有变量指向他时,垃圾收集器会最终删除这个表并重用其占用的内存。
Lua 不会进行隐藏拷贝或创建新表,操作的都是指向表的指针。
二、元素
1、键
表的键可以具有不同的类型,并且可以按需增长容纳新的元素。
如果 table 是一个序列,则下标是从 1 开始,切记不是从 0 开始。
不能用 nil 作为键,否则会抛 table index is nil 错误。
2、值
表的值可以通过赋值 nil 进行删除原有的项。
3、获取元素
第一种: table[key]
类似 ja va 、 kotlin 的 map 取值,如果 key 对应的值并不存在,则返回 nil。
第二种: table.key
这种取值等价于 table["key"],记得这里是字符串,而不是 table[key]
table[key] 和 table.key 区别
两种方式从使用角度来说没有任何区别。
从语义上说,table[key] 表示表可以使用任意字符串作为键。
table.key 表示表是被当作结构体使用,表实际上由固定的、预先定义的键组成集合。
k = "jiang"
a = {}
a[k] = 28
a[29] = "xiao"
-------------
-- 这里的 a 表有以下内容
-- "jiang" --> 28
-- 29 --> "xiao"
-------------
print(a[k]) --> 28
print(a.k) --> nil a.k 相当于 a["k"],所以就没有值
print(a.jiang) --> 28 a.jiang 相当于 a["jiang"]
4、数值作为键
任何能够被转换为整型的浮点数都会被转换成整型数(和之前数值一章的分享不谋而合)。
c = {}
c[2.0] = 10
print(c[2]) --> 10
三、表构造器
无论用哪种构造的表,都可以用 nil 赋予到对应的 key 删除对应的值。
空构造器
table1 = {}
列表式
这种方式运行速度更快一点(相比于记录式),因为能够提前判断表大小。
键会是从 1 开始往上递增的值。
-- 列表式,键会是从 1 开始往上递增的值
table2 = { "Jiang", "peng", "yong", } -- 最有的逗号是合法的,但不会被当作元素
--> 表结构
--> 1 -- "Jiang"
--> 2 -- "peng"
--> 3 -- "yong"
记录式
key 值会被当作字符串使用。
例如下面的 a key,最终形态是 “a”,所以可以使用 table3.a。
table3 = { a = "1", b = 20, c = "3" }
print("table3 length: " .. #table3) --> table3 length: 0 -- 因为 lua 表并不会进行维护长度,只会记录序列的下标作为表的长度
print(table3.a, table3["b"], table3.c) --> 1 20 3
--> 表结构
--> "a" -- "1"
--> "b" -- 20
--> "c" -- "3"
混合两种
混合使用并不会有冲突。
列表式的记录会从下标为 1 开始累加,记录式则还是继续使用自己的 key。
table4 = { name = "江澎涌", { 170, "cm" }, age = 28, { "专业", "软件工程" } }
print("table4 length: " .. #table4) --> table4 length: 2
print(table4.name, table4.age, table4[1][1], table4[2][2]) --> 江澎涌 28 170 软件工程
通用式
这种方式最为灵活,虽然使用起来麻烦些。
即通过方括号括起来的表达式显示地指定每一个索引
可以使用一些 “特殊字符” 或 “负数” 一类进行作为 key。
也可以在方括号中使用计算表达式,使用其结果作为 key 值。
table5 = { [-1] = "j", "i", ["a"] = "a", "n", c = "g" }
print("table5 length: " .. #table5) --> table5 length: 2
print(table5[1], table5[-1]) --> i j
四、表长度
table 没有维护一个类似 ja va 、 kotlin 中 map 的 size 的尺寸。
所以我们需要自己进行维护变量进行存储,可以存放在下面几个地方:
存储在一个常量中
存放在其他变量或数据结构中
存放在 table 中某个非数值类型的字段中,一般使用 “n” 作为 key
1、序列长度
序列是指不存在空洞(nil,所有的元素都不为nil)的有序列表。
序列可以使用 #table 进行获取长度。
不包括数值类型 key 的 table 就是长度为零的序列。
处理有空洞的列表则需要自行维护长度,不然 #table 不可靠
从下面代码段的最后不难看出,空洞的table长度已然不可靠。
毕竟nil的行为程序不好界定,程序猿究竟是想表达删除(这种情况下长度不应算该值),还是有意让该key值为nil(如此长度则应算该值)。
总之,若能确保是无空洞序列,就可以用“#”计算长度,否则就得自行维护了。
sequence = {}
for i = 1, 10 do
sequence[i] = i * i;
end
print("sequence size(没有空洞): " .. #sequence) --> sequence size(没有空洞): 10
sequence[5] = nil
print("sequence size(存在空洞,[5] = nil ): " .. #sequence) --> sequence size(存在空洞,[5] = nil ): 10 (其实没有 10 个值)
sequence[10] = nil
print("sequence size(存在空洞,[10] = nil ): " .. #sequence) --> sequence size(存在空洞,[10] = nil ): 9 (删除了最后一个,其实这里第 5 个和第 10 个都被删除了)
sequence[11] = 11 * 11
print("sequence size(存在空洞,[11] = 11*11 ): " .. #sequence) --> sequence size(存在空洞,[11] = 11*11 ): 11
sequence[10] = 100
print("sequence size(存在空洞,[100] = 100 ): " .. #sequence) --> sequence size(存在空洞,[100] = 100 ): 11
2、遍历计算长度
利用 pairs 会将所有的元素都遍历一次的特性,进行计算 table 中有多少元素。
pairs 在下一小节进行分享。
function table_leng(t)
local leng = 0
for k, v in pairs(t) do
leng = leng+1
end
return leng;
end
五、表遍历方式
三种遍历方式
1、paris
因底层实现问题,pairs 不会确保顺序,可能每次遍历结果都不同。
但每个元素一定会出现一次。
table5 = { 10, print, x = 12, k = "hi" }
for k, v in pairs(table5) do
print(k, "-->", v)
end
--> 1 --> 10
--> 2 --> function: 0x109cdeac0
--> x --> 12
--> k --> hi
2、ipairs
列表可以用 ipairs。
ipairs 会确保顺序进行,不是数字或是不连续(有空洞)则会被跳过。
print("ipairs 遍历")
table6 = { 10, print, 12, "hi"}
table6[10] = 111
table6["a"] = 100
for i, v in ipairs(table6) do
print(i, "-->", v)
end
--> ipairs 遍历
--> 1 --> 10
--> 2 --> function: 0x106f13ac0
--> 3 --> 12
--> 4 --> hi
3、序列下标遍历
table6 = { 10, print, 12, "hi" }
for i = 1, #table6 do
print(i, "-->", table6[i])
end
--> 序列数值遍历
--> 1 --> 10
--> 2 --> function: 0x106f13ac0
--> 3 --> 12
--> 4 --> hi
六、安全操作符
Lua 中没有安全操作符,不像 kotlin 中有 . 这样的操作。
但可以通过 nullable or default 的格式进行操作,例如下面操作。
E = {}
company = { }
zip = (((company or E).director or E).address or E).zipcode
类似 kotlin 中
var zip = company.director.address.zipcode
举个例子
这里就是利用了 or 的特性。
print("模拟安全操作: ")
----- 安全操作 -------
E = {}
company = nil
zipcode = (((company or E).director or E).address or E).zipcode or "default"
print(zipcode) --> default
company = { director = { address = { zipcode = "10080" } } }
zipcode = (((company or E).director or E).address or E).zipcode or "default"
print(zipcode) --> 10080
七、表标准库操作
只针对列表、序列操作,所有的操作下标开始是 1。
1、insert(table, index, item)
在 table 的 index 下标插入 item。
如果 index 越界了,则会抛出 bad argument #2 to 'insert' (position out of bounds)。
table7 = { 10, 20, 30 }
showTable(table7) --> [1]=10, [2]=20, [3]=30,
table.insert(table7, 2, 909)
showTable(table7) --> [1]=10, [2]=909, [3]=20, [4]=30,
如果不设置插入下标,则默认插在末尾。
table.insert(table7, 50)
showTable(table7) --> [1]=10, [2]=909, [3]=20, [4]=30, [5]=50,
2、remove(table, index)
移除 table 的 index 下标的元素,会有一个返回值,即被移除的元素。
则会抛出 bad argument #1 to 'remove' (position out of bounds)。
table.remove(table7, 3)
showTable(table7) --> [1]=10, [2]=909, [3]=30, [4]=50,
如果不设置下标参数,则移除末尾。
table.remove(table7)
showTable(table7) --> [1]=10, [2]=909, [3]=30,
3、move(table, startIndex, endIndex, newIndex)
move 只是负责移动元素,并不会附带删除
如果需要删除,则需要自行对元素进行设置为 nil。
将 table 中从 startIndex 到 endIndex 的元素( [ startIndex, endIndex ] ),复制到 newIndex 下标开始。
move 模拟在开头插入元素
table.move(table7, 1, #table7, 2)
table7[1] = 0
showTable(table7) --> [1]=0, [2]=10, [3]=909, [4]=30,
move 模拟删除第一个元素,记得要将末尾进行 nil 删除,否则最后元素还存在
table.move(table7, 2, #table7, 1)
table7[#table7] = nil
showTable(table7) --> [1]=10, [2]=909, [3]=30,
使用 move 可以进行 table 间的拷贝,即使用 table(table, startIndex, endIndex, newIndex, newtable)
需要多传入一个 table。
第四个参数指定的是 table 开始赋值的下标。
-- move 将表 a 拷贝到表 b , 可以通过 (#b + 1) 将元素接到表 b 末尾
table8 = { 20, 20, 30, 40, 50 }
table.move(table7, 1, #table7, #table8 + 1, table8)
showTable(table7) --> [1]=10, [2]=909, [3]=30,
showTable(table8) --> [1]=20, [2]=20, [3]=30, [4]=40, [5]=50, [6]=10, [7]=909, [8]=30,
4、sort(table, sortfunction)
对 table 排序。
table9 = {
{ name = "xiao peng you", age = 20 },
{ name = "zinc", age = 27 },
{ name = "jiang peng yong", age = 28 },
}
for i, v in ipairs(table9) do
print(i, "-->", v.name, "--", v.age)
end
--> 1 --> xiao peng you -- 20
--> 2 --> zinc -- 27
--> 3 --> jiang peng yong -- 28
table.sort(table9, function(a, b)
return #a.name > #b.name
end)
for i, v in ipairs(table9) do
print(i, "-->", v.name, "--", v.age)
end
--> 1 --> jiang peng yong -- 28
--> 2 --> xiao peng you -- 20
--> 3 --> zinc -- 27
值得注意
使用 insert 和 remove 函数时,如果针对中间元素进行操作,则会导致后面的元素移动,会有额外的开销。
八、写在最后
Lua 项目地址:Github传送门
公众号搜索 “江澎涌” 可以更快的获取到后续的更新文章
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- 迅捷路由器怎么调信号最强,设置时要注意什么?
- 时间:2026-08-27
-
- vivo浏览器怎么卸不掉?原因和解决方法在这里
- 时间:2026-08-27
-
- OPPO R11s黑屏了,怎么强制恢复出厂设置?
- 时间:2026-08-27
-
- 飞利浦显示器包装盒有生产日期和保修期吗?怎么看?
- 时间:2026-08-27
-
- 联想新平板开机必须联网吗?怎么做?
- 时间:2026-08-27
-
- 平板横竖屏切换设置与问题解决
- 时间:2026-08-27
-
- 移动电源容量怎么测?要准备哪些工具?
- 时间:2026-08-27
-
- 荣耀90 Pro防水吗?防水级别多少?怎么用才安全
- 时间:2026-08-27
精选合集
更多大家都在玩
大家都在看
更多-
- 蚂蚁新村小课堂今日答案9月30日 职业分类大典中工种与职业的关系是
- 时间:2026-09-30
-
- 蚂蚁新村2026年9月30日答案最新
- 时间:2026-09-30
-
- 蚂蚁庄园答案2026年10月1日
- 时间:2026-09-30
-
- 蚂蚁庄园今天答题答案2026年10月1日
- 时间:2026-09-30
-
- 蚂蚁庄园今日答案2026年10月1日
- 时间:2026-09-30
-
- “国庆”一词最早见于我国哪个朝代 蚂蚁庄园今日答案10.1
- 时间:2026-09-30
-
- 小鸡答题今天的答案是什么2026年10月1日
- 时间:2026-09-30
-
- 蚂蚁庄园每日答题答案2026年10月1日
- 时间:2026-09-30
