24

Lua table - DaemonCoder

 4 years ago
source link: https://www.daemoncoder.com/a/Lua%20table/4d6a413d?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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'

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK