Lua 小白入门教程Lua 小白入门教程
首页
基础教程
实战进阶
编程指南
首页
基础教程
实战进阶
编程指南
  • 基础教程

    • 📚 基础教程
    • 第1章 - Lua 是什么?
    • 第2章 - 环境搭建
    • 第3章 - 变量与数据类型
    • 第4章 - 运算符与表达式
    • 第5章 - 流程控制
    • 第6章 - 函数
    • 第7章 - Table(表)
    • 第8章 - 字符串与模式匹配

第7章 - Table(表)

嗨,朋友!我是长安。

Table 是 Lua 中最重要、最核心的数据结构——没有之一!在 Java 中你有 Array、List、Map、Set、Object……但在 Lua 中,这些全部由 Table 一个数据结构搞定。

🤔 Table 是什么?

简单来说,Table 就是一个关联数组,它可以用任何值(除了 nil)作为键,也可以存储任何值。

Java 数据结构Lua 实现方式
int[] 数组Table(整数索引)
ArrayListTable(整数索引)
HashMapTable(键值对)
Object 对象Table(键值对)
HashSetTable(值作为键)

📦 创建 Table

-- 空表
local t = {}

-- 数组风格(索引从 1 开始!不是 0!)
local fruits = {"苹果", "香蕉", "橘子"}
print(fruits[1])    -- 苹果(不是 fruits[0]!)
print(fruits[2])    -- 香蕉
print(fruits[3])    -- 橘子

-- 字典风格
local person = {
    name = "长安",
    age = 25,
    job = "Java开发"
}
print(person.name)      -- 长安
print(person["age"])    -- 25(另一种访问方式)

Java 程序员最大的坑

Lua 的数组索引从 1 开始,不是 0! 这是 Java 程序员最容易犯错的地方。

local arr = {"a", "b", "c"}
print(arr[0])   -- nil(不是 "a"!)
print(arr[1])   -- a(这才是第一个元素)

📋 Table 作为数组

local numbers = {10, 20, 30, 40, 50}

-- 获取长度
print(#numbers)    -- 5

-- 遍历数组(用 ipairs)
for i, v in ipairs(numbers) do
    print(i, v)
end
-- 1  10
-- 2  20
-- 3  30
-- 4  40
-- 5  50

-- 添加元素
table.insert(numbers, 60)           -- 在末尾添加
table.insert(numbers, 1, 5)         -- 在位置 1 插入

-- 删除元素
table.remove(numbers, 1)            -- 删除位置 1 的元素
local last = table.remove(numbers)  -- 删除并返回最后一个元素

-- 排序
table.sort(numbers)                 -- 升序排序
table.sort(numbers, function(a, b)  -- 降序排序
    return a > b
end)
// Java 等价操作
List<Integer> numbers = new ArrayList<>(Arrays.asList(10, 20, 30, 40, 50));

// 获取长度
System.out.println(numbers.size());  // 5

// 遍历
for (int i = 0; i < numbers.size(); i++) {
    System.out.println((i+1) + " " + numbers.get(i));
}

// 添加/删除
numbers.add(60);
numbers.add(0, 5);
numbers.remove(0);

// 排序
Collections.sort(numbers);
Collections.sort(numbers, Collections.reverseOrder());

📖 Table 作为字典(Map)

local config = {
    host = "localhost",
    port = 8080,
    debug = true
}

-- 访问值(两种方式)
print(config.host)          -- localhost
print(config["port"])       -- 8080

-- 修改值
config.port = 9090

-- 添加新键值对
config.timeout = 3000

-- 删除键值对(设置为 nil)
config.debug = nil

-- 遍历所有键值对(用 pairs)
for key, value in pairs(config) do
    print(key .. " = " .. tostring(value))
end

-- 检查键是否存在
if config.host then
    print("host 存在: " .. config.host)
end
// Java 等价操作
Map<String, Object> config = new HashMap<>();
config.put("host", "localhost");
config.put("port", 8080);
config.put("debug", true);

// 访问
System.out.println(config.get("host"));

// 修改 / 添加 / 删除
config.put("port", 9090);
config.put("timeout", 3000);
config.remove("debug");

// 遍历
for (Map.Entry<String, Object> entry : config.entrySet()) {
    System.out.println(entry.getKey() + " = " + entry.getValue());
}

// 检查
if (config.containsKey("host")) {
    System.out.println("host 存在: " + config.get("host"));
}

🏗️ Table 作为对象

-- 用 Table 模拟一个"对象"
local player = {
    name = "战士",
    hp = 100,
    attack = 25,

    -- 方法:注意用冒号定义(自动传入 self)
    takeDamage = function(self, damage)
        self.hp = self.hp - damage
        print(self.name .. " 受到 " .. damage .. " 点伤害,剩余 HP: " .. self.hp)
    end
}

-- 调用方法(用冒号调用,自动传入 self)
player:takeDamage(30)    -- 战士 受到 30 点伤害,剩余 HP: 70

-- 等价于:
player.takeDamage(player, 30)  -- 用点号需要手动传 self

冒号语法糖

Lua 中 : 是一个语法糖:

  • 定义时 function obj:method() 等价于 function obj.method(self)
  • 调用时 obj:method() 等价于 obj.method(obj)

类似于 Java 中方法自动拥有 this 引用。

🔄 嵌套 Table

-- 嵌套结构(类似 Java 中对象嵌套)
local company = {
    name = "科技公司",
    employees = {
        {name = "张三", age = 28, dept = "后端"},
        {name = "李四", age = 25, dept = "前端"},
        {name = "王五", age = 30, dept = "后端"},
    },
    address = {
        city = "北京",
        street = "中关村大街"
    }
}

-- 访问嵌套数据
print(company.name)                        -- 科技公司
print(company.address.city)                -- 北京
print(company.employees[1].name)           -- 张三
print(company.employees[2].dept)           -- 前端

-- 遍历员工
for i, emp in ipairs(company.employees) do
    print(string.format("%d. %s (%s部门)", i, emp.name, emp.dept))
end
-- 1. 张三 (后端部门)
-- 2. 李四 (前端部门)
-- 3. 王五 (后端部门)

📊 Table 常用操作速查

local t = {1, 2, 3, 4, 5}

-- 长度
print(#t)                    -- 5

-- 插入
table.insert(t, 6)           -- 末尾插入 6
table.insert(t, 1, 0)        -- 位置 1 插入 0

-- 删除
table.remove(t, 1)           -- 删除位置 1
table.remove(t)              -- 删除最后一个

-- 拼接(数组元素拼接为字符串)
local arr = {"Hello", "World", "Lua"}
print(table.concat(arr, ", "))  -- Hello, World, Lua
-- 类似 Java 的 String.join(", ", arr)

-- 排序
table.sort(t)                -- 升序
table.sort(t, function(a, b) return a > b end)  -- 降序

-- 解包
local a, b, c = table.unpack({10, 20, 30})
print(a, b, c)               -- 10  20  30

💡 Table 的引用特性

Table 是引用类型,赋值不会复制,而是共享同一个 Table:

local a = {1, 2, 3}
local b = a           -- b 和 a 指向同一个 table!

b[1] = 100
print(a[1])           -- 100(a 也被改了!)

-- 如果要复制,需要手动遍历
local function shallowCopy(t)
    local copy = {}
    for k, v in pairs(t) do
        copy[k] = v
    end
    return copy
end

local c = shallowCopy(a)
c[1] = 999
print(a[1])           -- 100(a 不受影响)

Java 程序员应该很熟悉

这和 Java 的引用类型完全一样!List<Integer> b = a; 也是引用赋值,修改 b 会影响 a。

📝 小结

  • Table 是 Lua 唯一的数据结构,可以当数组、字典、对象用
  • 数组索引从 1 开始,不是 0!
  • 用 ipairs 遍历数组,用 pairs 遍历字典
  • 冒号 : 是语法糖,自动传入 self 参数
  • Table 是引用类型,赋值不会复制
  • # 获取数组长度,table.insert/remove/sort 操作数组

➡️ 下一步

Table 掌握了!下一章我们来学习 字符串与模式匹配,看看 Lua 处理字符串有多灵活。

💪 练习题

  1. 创建一个数组 Table,存储 5 个城市名称,打印第 3 个城市。
  2. 创建一个字典 Table 表示一本书(书名、作者、价格),打印所有信息。
  3. 用 Table 实现一个简单的"栈"(push 和 pop 操作)。
  4. Lua 数组索引从几开始?为什么这对 Java 程序员很重要?

答案提示

  1. local cities = {"北京","上海","广州","深圳","杭州"} → print(cities[3])
  2. local book = {title="Lua入门", author="长安", price=59} + pairs 遍历
  3. push: table.insert(stack, value), pop: table.remove(stack)
  4. 从 1 开始。Java 从 0 开始,容易写成 arr[0]导致取到 nil
最近更新: 2026/2/27 17:54
Contributors: 王长安
Prev
第6章 - 函数
Next
第8章 - 字符串与模式匹配