Lua table - 看似简单的Lua表,竟然还有这么多没有留意的点

fe4f994e59c213da8112616efa798ec4.png

table就是Lua语言提供的数组,但是不同于Java、C++等语言,Lua table不仅是数组,还可以是Java语言中的Map,也就是table也可以存储键值对。这一点和PHP语言相似,Lua中的数组也当作键值对来处理,数组元素的键是数字。因为把 Lua 中的 table 叫作表更合适。

table 的定义

table用花括号来定义,元素用逗号隔开,最后一个元素后可以加逗号,也可以不加。table的键和值都可以是任意类型(注意,键也可以是任意类型)。

-- 定义空table
local empty_table = {}
-- 定义一个字符串数组
local array = {'daemon', 'coder'}
-- 数组元素也可以多种类型混合
local mix_array = {'Nice', 666}
-- 元素是数组的数组,可以用这种方式定义多维数组。
local matrix = {
    {11, 12, 13, 14},
    {21, 22, 23, 24},
    {31, 32, 33, 34, 35, 36},
}

定义一个键值对形式的数组,键和值用等号隔开,等号左侧是键,右侧是值。注意字符串形式的key不需要像字符串定义一样用引号:

local map = {name = 'DaemonCoder', url = 'daemoncoder.com'}
--[[
下面这样定义会有语法错误:
local map = {'name' = 'DaemonCoder', 'url' = 'daemoncoder.com'}
]]

如果不得不用引号包起来时(比如字符串中包含了等号等特殊符号),把键用方括号括起来,同时键值也要用字符串的定义格式加引号。

local map = {['name'] = 'DaemonCoder', ['url'] = 'daemoncoder.com'}

其实[]形式的键,不仅可以用字符串,还可以是任意类型,甚至是一个表达式:

local table_key = {[{}] = {}} -- 键和值都是table类型
local int_key = {[0] = {}} -- 键是int类型
local function_key = {[function() end] = {}} -- 键是函数类型
local expression_key = {
    -- 一个空table作为key
    [{}] = {},

    -- 用一个变量作为key
    [empty_table] = {},

    -- 调用一个函数,返回值作为key
    [table.concat(empty_table, '')] = {},
}
-- 注意上面这些写法都是把键用[]包起来的情况,没有[]的键都是字符串,不能用这样写法。

table中也可以同时包含键值对和单个的值,没有指定键的,用默认数字下标,从1开始,注意从1开始(程序猿的世界里,习惯了从0开始,从1开始这么自然的事情,竟然觉得有点奇葩,有木有?)。

local mix = {'AAA', name='daemoncoder', 'BBB'}
-- 上面 'AAA'、'BBB' 使用默认的数字键,'AAA'的键为1,'BBB'的键为2。

table 的访问

table 读取或设置指定键的值时,可以用方括号来指定键,对于符合标识符命名规范的键,还可以用点号来指定,看下面示例:

local t = {"zhang3", age = 18}
print(t[1], t['age']) -- zhang3 18
t['age'] = 19
print(t.age)   -- 19
-- print(t.1)  -- 语法错误,1 不是合法的标识符,不能用点号访问,只能用 t[1]
print(t[1])

print(t.name)  -- nil  不存在的key为nil
t.name = "zhang3" -- 给table设置新的值

可以用for循环配合 pairs() 或 ipairs() 来遍历table。

ipairs() 用于遍历键为连续数字的table,键从1开始,依次递增,直到某个键对应的值为 nil 就停止,即使还有其他键为数字的元素没有被遍历到,也会停止。因此,键如果不是从1递增的连续数字,要谨慎使用ipairs(),看下面使用示例:

local t = {"111", "222", "333"}
for i, v in ipairs(t) do
    print(i, v)
end
--[[
输出:
1   111
2   222
3   333
]]

local t = {"111", "222", nil, "333"}
for i, v in ipairs(t) do
    print(i, v)
end
--[[
输出
1   111
2   222
]]

-- 下面这个什么也不会输出,因为 t[1] 为 nil
local t = {a="AAA", b="BBB", c="CCC"}
for i, v in ipairs(t) do
    print(i, v)
end

pairs() 可以用于遍历任意table,遇到值为 nil 的元素时,会跳过,而不是停止。仔细想想这是合理的,值为 nil 和 table 中不存在这个键是一样的,因为 Lua 未定义的变量都为 nil。

需要注意的是,pairs() 的访问顺序并不是table中各字段的定义顺序,而是根据键的哈希值来的,所以看上去可能是『乱序』,看下面示例:

local t = {a="AAA", b="BBB", c="CCC"}
for k, v in pairs(t) do
    print(k, v)
end
--[[
下面是输出,和定义的顺序不同:
b   BBB
a   AAA
c   CCC
]]

local t = {"111", "222", nil, "333"}
for i, v in pairs(t) do
    print(i, v)
end
--[[
下面是输出,注意"333"是可以被输出的,值为 nil 的会被跳过。
1   111
2   222
4   333
]]

table 的长度

当table是一个下标从1递增的数组时,可以用#号来计算的长度。但是和ipairs相同,仅限于键值从1开始连续递增的数组,其他情况可能和你的预期不一致,要谨慎使用。看下面示例:

print(#{"111", "222", "333"})       -- 3
print(#{"111", "222", nil, "333"})  -- 4
print(#{"111", "222", nil, nil, "333"})  -- 2
print(#{a="AAA", b="BBB", c="CCC"}) -- 0
print(#{"111", [4]="222", [7]="333"}) -- 4
print(#{"111", [5]="222", [7]="333"}) -- 1
print(#{"111", [3]="222", [4]="333"}) -- 4
print(#{[4]="111", [5]="222", [6]="333"}) -- 6

全局变量table

Lua提供了一个全局变量table,里面定义了一些常用的函数。

table.insert()

向数组指定位置插入元素,定义如下:

table.insert(list: table, pos: integer, value: any)

  • list:要操作的数组

  • pos:要插入的下标,原来此位置及以后的元素,都依次向后移,也就是把键加1。

  • value:要插入的值

local t = {1, 2, nil, 4, 5}
table.insert(t, 4, "new")   -- {1, 2, nil, 4, "new", 5}
table.insert(t, 3, "new2")  -- {1, 2, "new2", nil, 4, "new", 5}

table.concat()

把table中指定范围的元素,用指定的字符串拼接起来,定义如下:

table.concat(list: table, sep: string, i: integer, j: integer)

  • list:要操作的table

  • sep:指定用于间隔元素的字符串

  • i:待拼装元素范围的起始下标(包含)

  • j:待拼装元素范围的结束下标(包含)

print(table.concat({"aaa", "bbb", "ccc", "ddd"}, '|')) -- aaa|bbb|ccc|ddd
print(table.concat({"aaa", "bbb", "ccc", "ddd"}, '|', 2)) -- aaa|bbb|ccc|ddd
print(table.concat({"aaa", "bbb", "ccc", "ddd"}, '|', 2, 3)) -- bbb|ccc|ddd
-- print(table.concat({"aaa", "bbb", "ccc", "ddd"}, '|', 2, 5))
-- table.concat() 指定的下标不能越界,不然报错:
-- invalid value (nil) at index 5 in table for 'concat'

转载请注明出处,本文原始链接:https://www.daemoncoder.com/

点击下方阅读原文,发现更多优质内容。扫码关注公共号,第一时间收到优质内容哦~

57a779399d7fa7816a7c1ad9721e5706.jpeg

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值