第 7 章 表
第 7 章 表
表是 Lua 唯一的内置复合数据结构。它同时承担数组、字典、集合和对象等职责,是后续模块与面向对象实现的基础。
创建与访问表
local user = {
name = "Ada",
age = 30,
["is-active"] = true
}
print(user.name)
print(user["age"])
user.email = "ada@example.com"
user["age"] = 31
键可以是数字、字符串、布尔值、表或函数。表键按引用比较:
local key = {}
local data = {}
data[key] = "value"
print(data[key]) -- value
print(data[{}]) -- nil
数组、序列与长度
以连续正整数为键的表通常称为序列:
local languages = { "Lua", "C", "Rust" }
print(languages[1]) -- Lua
print(languages[2]) -- C
print(#languages) -- 3
Lua 索引从 1 开始,这是新手最容易出错的地方。添加元素可使用 #values + 1:
languages[#languages + 1] = "Go"
如果表中存在空洞,# 的结果没有可靠定义:
local sparse = {}
sparse[1] = "a"
sparse[3] = "c"
-- sparse[2] 为 nil,#sparse 可能返回 1 或 3
需要对稀疏数据计数时,显式维护长度或遍历计数。
字典与嵌套数据
local config = {
server = {
host = "127.0.0.1",
port = 8080
},
features = {
cache = true,
tracing = false
}
}
print(config.server.host)
print(config.features.cache)
深层字段可能为 nil,直接连续索引会报错:
local function safeGet(value, path)
local current = value
for key in path:gmatch("[^%.]+") do
if type(current) ~= "table" then
return nil
end
current = current[key]
end
return current
end
print(safeGet(config, "server.port"))
print(safeGet(config, "server.timeout.value"))
遍历表
数组使用 ipairs:
for index, value in ipairs(languages) do
print(index, value)
end
字典使用 pairs:
for key, value in pairs(config.server) do
print(key, value)
end
遍历顺序不应依赖。需要稳定排序时,先收集键再排序:
local keys = {}
for key in pairs(config.server) do
keys[#keys + 1] = key
end
table.sort(keys)
for _, key in ipairs(keys) do
print(key, config.server[key])
end
表操作实战
深拷贝
local function deepCopy(value, seen)
if type(value) ~= "table" then
return value
end
seen = seen or {}
if seen[value] then
return seen[value]
end
local copy = {}
seen[value] = copy
for key, item in pairs(value) do
copy[deepCopy(key, seen)] = deepCopy(item, seen)
end
return copy
end
seen 用于处理循环引用,避免递归无限展开。
按字段分组
local function groupBy(items, keySelector)
local groups = {}
for _, item in ipairs(items) do
local key = keySelector(item)
groups[key] = groups[key] or {}
groups[key][#groups[key] + 1] = item
end
return groups
end
移除元素
删除数组元素后可能产生空洞。需要保持连续序列时,可以从后向前遍历:
local values = { 1, 2, 3, 4, 5 }
for index = #values, 1, -1 do
if values[index] % 2 == 0 then
table.remove(values, index)
end
end