表基础 #

一、表概述 #

1.1 什么是表 #

表(Table)是 Lua 中唯一的数据结构,它可以用来表示:

  • 数组
  • 字典/映射
  • 对象
  • 模块
  • 命名空间
lua
-- 表是 Lua 的核心数据结构
local t = {}  -- 创建空表

1.2 表的特点 #

  • 动态:可以随时添加和删除字段
  • 灵活:键可以是除 nil 外的任何类型
  • 引用类型:变量存储的是表的引用

二、创建表 #

2.1 空表 #

lua
-- 创建空表
local t1 = {}
local t2 = table.new and table.new(0, 0) or {}  -- 预分配(Lua 5.3+)

2.2 数组风格 #

lua
-- 数组风格创建
local arr1 = {1, 2, 3, 4, 5}
local arr2 = {"a", "b", "c"}

-- 索引从 1 开始
print(arr1[1])  -- 1
print(arr1[5])  -- 5

2.3 字典风格 #

lua
-- 字典风格创建
local person = {
    name = "张三",
    age = 25,
    city = "北京"
}

print(person.name)   -- 张三
print(person["age"]) -- 25

2.4 混合风格 #

lua
-- 混合风格
local mixed = {
    1, 2, 3,           -- 数组部分
    name = "Lua",      -- 字典部分
    [10] = "第十个",   -- 指定索引
    ["key with space"] = "值"  -- 字符串键
}

print(mixed[1])       -- 1
print(mixed.name)     -- Lua
print(mixed[10])      -- 第十个

2.5 嵌套表 #

lua
-- 嵌套表
local company = {
    name = "TechCorp",
    address = {
        city = "北京",
        street = "中关村大街"
    },
    employees = {
        {name = "张三", age = 30},
        {name = "李四", age = 28}
    }
}

print(company.address.city)       -- 北京
print(company.employees[1].name)  -- 张三

三、访问表 #

3.1 点语法 #

lua
local person = {name = "张三", age = 25}

-- 点语法访问
print(person.name)  -- 张三

-- 点语法赋值
person.city = "北京"
print(person.city)  -- 北京

3.2 方括号语法 #

lua
local person = {name = "张三", age = 25}

-- 方括号访问
print(person["name"])  -- 张三

-- 方括号赋值
person["city"] = "北京"

-- 动态键名
local key = "name"
print(person[key])  -- 张三

3.3 两种语法的区别 #

lua
local t = {}

-- 点语法:键必须是有效的标识符
t.name = "Lua"       -- 正确
-- t.123 = "数字"    -- 错误
-- t.my-key = "连字符" -- 错误

-- 方括号语法:键可以是任意类型
t[123] = "数字键"       -- 正确
t["my-key"] = "连字符"  -- 正确
t[function() end] = "函数键"  -- 正确(但不推荐)

-- 访问时也需要使用方括号
print(t[123])        -- 数字键
print(t["my-key"])   -- 连字符

四、表的遍历 #

4.1 ipairs 遍历数组 #

lua
local arr = {"a", "b", "c", "d", "e"}

-- ipairs:遍历数组部分(从 1 开始连续整数索引)
for i, v in ipairs(arr) do
    print(i, v)
end
-- 1    a
-- 2    b
-- 3    c
-- 4    d
-- 5    e

-- 注意:ipairs 遇到 nil 会停止
local sparse = {1, 2, nil, 4}
for i, v in ipairs(sparse) do
    print(i, v)
end
-- 只输出:1 1  和  2 2

4.2 pairs 遍历所有 #

lua
local t = {
    a = 1,
    b = 2,
    c = 3,
    [1] = "first",
    [2] = "second"
}

-- pairs:遍历所有键值对
for k, v in pairs(t) do
    print(k, v)
end
-- 输出顺序不确定

4.3 数值 for 遍历 #

lua
local arr = {10, 20, 30, 40, 50}

-- 数值 for:适合已知长度
for i = 1, #arr do
    print(i, arr[i])
end

-- 逆序遍历
for i = #arr, 1, -1 do
    print(i, arr[i])
end

4.4 遍历嵌套表 #

lua
local matrix = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
}

-- 遍历二维数组
for i = 1, #matrix do
    for j = 1, #matrix[i] do
        io.write(matrix[i][j] .. " ")
    end
    io.write("\n")
end

五、表的长度 #

5.1 # 操作符 #

lua
-- 获取数组长度
local arr = {1, 2, 3, 4, 5}
print(#arr)  -- 5

-- 空表
print(#{})   -- 0

-- 字典长度
local dict = {a = 1, b = 2, c = 3}
print(#dict)  -- 0(# 不适用于字典)

5.2 长度的陷阱 #

lua
-- 稀疏数组
local sparse = {1, 2, nil, 4, 5}
print(#sparse)  -- 不确定,可能是 5 或 2

-- 正确计算元素数量
local function count_elements(t)
    local count = 0
    for _ in pairs(t) do
        count = count + 1
    end
    return count
end

print(count_elements({a = 1, b = 2, c = 3}))  -- 3

六、表的复制 #

6.1 浅拷贝 #

lua
-- 浅拷贝
local function shallow_copy(t)
    local copy = {}
    for k, v in pairs(t) do
        copy[k] = v
    end
    return copy
end

local original = {a = 1, b = {c = 2}}
local copy = shallow_copy(original)

copy.a = 10
print(original.a)  -- 1(不受影响)

copy.b.c = 20
print(original.b.c)  -- 20(受影响,因为嵌套表是引用)

6.2 深拷贝 #

lua
-- 深拷贝
local function deep_copy(t, visited)
    visited = visited or {}
    
    if type(t) ~= "table" then
        return t
    end
    
    if visited[t] then
        return visited[t]
    end
    
    local copy = {}
    visited[t] = copy
    
    for k, v in pairs(t) do
        copy[deep_copy(k, visited)] = deep_copy(v, visited)
    end
    
    return copy
end

local original = {a = 1, b = {c = 2}}
local copy = deep_copy(original)

copy.b.c = 20
print(original.b.c)  -- 2(不受影响)

七、表的操作 #

7.1 添加元素 #

lua
local t = {}

-- 直接赋值
t.name = "Lua"

-- 表尾添加(数组)
table.insert(t, "a")
table.insert(t, "b")

-- 指定位置插入
table.insert(t, 1, "first")

7.2 删除元素 #

lua
local t = {a = 1, b = 2, c = 3}

-- 设置为 nil
t.b = nil

-- 删除数组元素
local arr = {1, 2, 3, 4, 5}
local removed = table.remove(arr, 2)  -- 删除第 2 个
print(removed)  -- 2
print(arr[2])   -- 3

7.3 修改元素 #

lua
local t = {a = 1, b = 2}

-- 直接修改
t.a = 10

-- 批量修改
local function update(t, updates)
    for k, v in pairs(updates) do
        t[k] = v
    end
end

update(t, {a = 100, c = 300})
print(t.a, t.c)  -- 100    300

八、表的合并 #

8.1 合并两个表 #

lua
local function merge(t1, t2)
    local result = {}
    for k, v in pairs(t1) do
        result[k] = v
    end
    for k, v in pairs(t2) do
        result[k] = v
    end
    return result
end

local a = {x = 1, y = 2}
local b = {y = 20, z = 3}
local c = merge(a, b)
print(c.x, c.y, c.z)  -- 1    20    3

8.2 合并数组 #

lua
local function concat_arrays(...)
    local result = {}
    for i = 1, select("#", ...) do
        local arr = select(i, ...)
        for _, v in ipairs(arr) do
            table.insert(result, v)
        end
    end
    return result
end

local merged = concat_arrays({1, 2}, {3, 4}, {5, 6})
print(table.concat(merged, ", "))  -- 1, 2, 3, 4, 5, 6

九、表的序列化 #

9.1 转换为字符串 #

lua
local function serialize(t, indent)
    indent = indent or ""
    local result = {}
    
    table.insert(result, "{")
    
    for k, v in pairs(t) do
        local key
        if type(k) == "string" and k:match("^[%a_][%w_]*$") then
            key = k
        else
            key = "[" .. serialize(k) .. "]"
        end
        
        local value
        if type(v) == "table" then
            value = serialize(v, indent .. "  ")
        elseif type(v) == "string" then
            value = string.format("%q", v)
        else
            value = tostring(v)
        end
        
        table.insert(result, indent .. "  " .. key .. " = " .. value .. ",")
    end
    
    table.insert(result, indent .. "}")
    return table.concat(result, "\n")
end

local t = {name = "Lua", version = 5.4, features = {"fast", "light"}}
print(serialize(t))

十、总结 #

本章介绍了 Lua 表的基础知识:

  1. 表概述:Lua 唯一的数据结构
  2. 创建表:空表、数组、字典、混合、嵌套
  3. 访问表:点语法和方括号语法
  4. 遍历表:ipairs、pairs、数值 for
  5. 表长度:# 操作符及其陷阱
  6. 表复制:浅拷贝和深拷贝
  7. 表操作:添加、删除、修改、合并

表是 Lua 的核心,下一章我们将学习表作为数组的高级用法。

最后更新:2026-03-27