Skip to content

Lua 表

表(Tables)是 Lua 中唯一的数据结构机制,它们是语言的基础。表是一种高度灵活的关联数组(associative array)。这意味着它不仅可以用数字作为索引,还可以使用其他 Lua 值作为索引,例如字符串(strings)、布尔值(booleans),甚至其他表(tables)(除了 nil)。表用于表示普通数组(ordinary arrays)、列表(lists)、符号表(symbol tables)(字典/映射 - dictionaries/maps)、对象(objects)、包(packages)等。

Lua 中的表是动态的;它们的大小不固定,可以根据需要增长或缩小。它们常被称为对象,但理解它们与引用它们的变量是不同的很重要。

空表使用构造器表达式 {} 创建。

-- Create an empty table
local my_table = {}
-- Assign values using keys (indices)
my_table[1] = "Apple" -- Numeric key (array-like)
my_table["color"] = "Red" -- String key (dictionary-like)
my_table[true] = "Is a fruit" -- Boolean key
-- Access values using keys
print(my_table[1]) -- Output: Apple
print(my_table["color"]) -- Output: Red
-- Alternative syntax for string keys (if valid identifiers)
my_table.shape = "Round"
print(my_table.shape) -- Output: Round
-- Initialize a table with elements
local another_table = {
name = "Banana",
color = "Yellow",
peel_status = "Peeled",
10, -- equivalent to [1] = 10
20 -- equivalent to [2] = 20
}
print(another_table.name) -- Output: Banana
print(another_table[1]) -- Output: 10

Lua 中的变量本身不存储表,而是存储对表的引用。当你将一个表变量赋值给另一个变量时,两个变量引用内存中的同一个表。通过一个变量修改表会影响到另一个变量。

local t1 = { value = 10 }
local t2 = t1 -- t2 now refers to the same table as t1
t2.value = 20
print(t1.value) -- Output: 20 (since t1 and t2 point to the same table)
t1 = nil -- t1 no longer refers to the table
-- The table itself still exists because t2 refers to it.
print(t2.value) -- Output: 20
t2 = nil -- Now, no variable refers to the table.
-- Lua's garbage collector will eventually reclaim the memory used by the table.

示例:演示表的类型和引用

-- Simple empty table
local mytable = {}
print("Type of mytable is: " .. type(mytable)) -- Type of mytable is: table
mytable[1] = "Lua"
mytable["feature"] = "Tables"
print("mytable[1] is: " .. mytable[1]) -- mytable[1] is: Lua
print("mytable.feature is: " .. mytable.feature) -- mytable.feature is: Tables
-- alternatetable and mytable refer to the same table
local alternatetable = mytable
print("alternatetable[1] is: " .. alternatetable[1]) -- alternatetable[1] is: Lua
alternatetable.feature = "Powerful Tables"
print("mytable.feature is now: " .. mytable.feature) -- mytable.feature is now: Powerful Tables
-- Release reference from alternatetable
alternatetable = nil
print("alternatetable is: " .. tostring(alternatetable)) -- alternatetable is: nil
-- mytable is still accessible
print("mytable.feature is still: " .. mytable.feature) -- mytable.feature is still: Powerful Tables
mytable = nil -- Now the table is eligible for garbage collection
print("mytable is: " .. tostring(mytable)) -- mytable is: nil

Lua 提供了一个 table 库,其中包含用于操作表的函数,特别是当表被用作数组/列表时。

函数签名用途
table.concat(list [, sep [, i [, j]]])将 list (一个类数组表) 中从索引 i 到 j 的字符串元素连接起来。元素之间由 sep 分隔(默认为空字符串)。i 默认为 1,j 默认为 #list。
table.insert(list, [pos,] value)在 list 中插入 value 到 pos 位置。如果省略 pos,则插入到末尾。后续元素会向后移动。
table.remove(list [, pos])从 list 中移除 pos 位置的元素。如果省略 pos,则移除最后一个元素。返回被移除的元素。后续元素会向前移动。
table.sort(list [, comp])原地(in place)对 list 中的元素进行排序。可以提供一个可选的比较函数 comp(a,b),如果 a 应该在 b 之前,则该函数应返回 true。
table.pack(...)(Lua 5.2+)返回一个新表,其中所有参数存储在键 1、2 等位置,并有一个字段 ‘n’ 包含参数总数。
table.unpack(list [, i [, j]])(Lua 5.1 是 unpack,Lua 5.2+ 是 table.unpack)将给定 list 中从索引 i 到 j 的元素作为独立的返回值返回。i 默认为 1,j 默认为 #list。

注意:table.maxn 在 Lua 5.1 中已弃用,在 Lua 5.2 中已移除。要获取序列类表(从索引 1 开始且没有 nil 空洞的数组)的长度,请使用长度运算符 #。

表操作示例:

local words = {"Lua", "is", "awesome"}
print("Concatenated (default): " .. table.concat(words)) -- Luaisawesome
print("Concatenated with space: " .. table.concat(words, " ")) -- Lua is awesome
print("Concatenated with dash (subset): " .. table.concat(words, "-", 2, 3)) -- is-awesome

插入和移除 (table.insert, table.remove, # 运算符)

Section titled “插入和移除 (table.insert, table.remove, # 运算符)”
local fruits = {"banana", "orange", "apple"}
print("Initial #fruits:", #fruits) -- Initial #fruits: 3
-- Insert at the end
table.insert(fruits, "mango")
print("Fruit at index 4:", fruits[4], "(#fruits:", #fruits .. ")") -- Fruit at index 4: mango (#fruits: 4)
-- Insert at a specific position
table.insert(fruits, 2, "grapes")
print("Fruit at index 2:", fruits[2], "(#fruits:", #fruits .. ")") -- Fruit at index 2: grapes (#fruits: 5)
-- fruits is now: {"banana", "grapes", "orange", "apple", "mango"}
local removed_fruit = table.remove(fruits) -- Removes last element ("mango")
print("Removed last fruit:", removed_fruit, "(#fruits:", #fruits .. ")") -- Removed last fruit: mango (#fruits: 4)
-- fruits is now: {"banana", "grapes", "orange", "apple"}
local removed_at_pos = table.remove(fruits, 1) -- Removes first element ("banana")
print("Removed fruit at pos 1:", removed_at_pos, "(#fruits:", #fruits .. ")") -- Removed fruit at pos 1: banana (#fruits: 3)
-- fruits is now: {"grapes", "orange", "apple"}
local numbers = {5, 1, 100, 20, 3}
-- Default sort (ascending)
table.sort(numbers)
print("Sorted numbers (ascending):")
for i, v in ipairs(numbers) do print(string.format(" [%d] = %d", i, v)) end
-- Output: [1]=1, [2]=3, [3]=5, [4]=20, [5]=100
-- Custom sort (descending)
local names = {"Charlie", "Alice", "Bob"}
table.sort(names, function(a, b) return a > b end) -- Sort descending
print("\nSorted names (descending):")
for i, v in ipairs(names) do print(string.format(" [%d] = %s", i, v)) end
-- Output: [1]=Charlie, [2]=Bob, [3]=Alice

Lua 提供了两个主要的迭代器(iterators)用于遍历表:

  • **ipairs(t):**遍历表 t 中整数键 1, 2, ...(序列部分),直到第一个 nil 值。适用于数组。
  • **pairs(t):**以未指定顺序遍历表 t 中的所有键值对。用于字典类表或需要访问所有元素(包括非序列部分)时。
local mixed_table = {
[1] = "first",
[2] = "second",
name = "My Table",
[4] = "fourth after nil", -- ipairs will stop before this
color = "blue"
}
mixed_table[3] = "third" -- now sequence is 1,2,3
print("\nIterating with ipairs (sequence part):")
for index, value in ipairs(mixed_table) do
print(string.format(" Index: %s, Value: %s", tostring(index), tostring(value)))
end
print("\nIterating with pairs (all elements):")
for key, value in pairs(mixed_table) do
print(string.format(" Key: %s, Value: %s", tostring(key), tostring(value)))
end

更多资源:表是一个广泛的主题。官方 Lua 参考手册是关于表行为、构造器和 table 库所有细节的权威来源。