表格教程

lua-users home
wiki

表格是 Lua 中唯一的“容器”类型。它们是关联数组([1]),这意味着它们存储一组键值对。在键值对中,您可以将值存储在键下,然后使用该键检索该值。

创建表格

表格使用表格构造器创建,表格构造器使用花括号定义,例如 { } 。要定义一个空表格,我们可以执行以下操作。

> t = {}    -- construct an empty table and assign it to variable "t"
> print(t)
table: 0035AE18
注意,当显示表格的值时,只显示对象的类型和唯一 ID。要打印出表格的内容,我们必须显式地这样做。我们将在后面学习如何做到这一点。

使用表格

要访问表格中与键关联的值,可以使用 table[key] 语法

> t = {}
> t["foo"] = 123 -- assign the value 123 to the key "foo" in the table
> t[3] = "bar" -- assign the value "bar" to the key 3 in the table
> = t["foo"]
123
> = t[3]
bar

如果与键没有关联的值,则不会出错,而是结果将为 nil

> t = {}
> = t["foo"]
nil

您可以通过将 nil 赋值给值来从表格中删除键值对。

> t["foo"] = nil

任何值都可以用作键(不仅仅是数字和字符串),只要确保它不是 nil 或 NaN(非数字)即可

> t = {}
> k = {}
> f = function () end
> t[k] = 123
> t[f] = 456
> = t[k]
123
> = t[f]
456
> t[nil] = 123
stdin:1: table index is nil
stack traceback:
        stdin:1: in main chunk
        [C]: in ?
> t[0/0] = 123
stdin:1: table index is NaN
stack traceback:
        stdin:1: in main chunk
        [C]: in ?

但使用字符串常量作为键非常常见,因此有一个特殊的快捷语法

> t = {}
> t.foo = 123 -- same as t["foo"] (but not t[foo], which would use the variable foo as the key)
> = t.foo
123
> = t["foo"]
123
快捷语法仅在字符串由下划线、字母和数字组成,但不能以数字开头时才有效。

您也可以在 {} 语法中直接添加键值关联

> t = {["foo"] = "bar", [123] = 456}
> = t.foo
bar
> = t[123]
456

在 {} 中,对于字符串键也有一种语法快捷方式,只要字符串符合与 . 语法相同的规则

> t = {foo = "bar"} -- same as ["foo"]="bar" (but not [foo]="bar" , that would use the variable foo)
> = t["foo"]
bar

要循环遍历表格中的所有键值对,请使用 pairs 迭代器

> t = {foo = "bar", [123] = 456}
> for key,value in pairs(t) do print(key,value) end
foo bar
123 456
使用 pairs 循环时的顺序是未定义的。仅仅因为您在添加另一个项目后添加了一个项目,并不意味着它们使用 pairs 的顺序就是如此。

pairs 循环中,可以安全地重新分配现有键或删除它们(通过将它们赋值为 nil),但不能添加新键(以前具有 nil 值的键)。

表格作为数组

首先要记住,表仍然只是键值对容器,因为 Lua 实际上没有数组类型。但表可以像数组一样对待,这里解释了这一点。

表构造函数可以包含用逗号分隔的对象列表来创建一个“数组”。

> t = {"a", "b", "c"}
> = t[1]
a
> = t[3]
c
这是一种语法快捷方式,用于
> t = {[1]="a", [2]="b", [3]="c"}
> = t[1]
a
> = t[3]
c
所以它仍然只是一个键值关联。

你也可以将数组语法与通常的键=值语法混合使用。

> t = {"a", "b", [123]="foo", "c", name="bar", "d", "e"}
> for k,v in pairs(t) do print(k,v) end
1       a
2       b
3       c
4       d
5       e
123     foo
name    bar

第一个索引是数字 1,这与大多数从数字 0 开始的其他语言不同。之所以选择它,是因为它通常更直观。之所以选择它,还因为它只是一个键,而不是从开头开始的偏移量。大多数语言实现了实际的数组类型。

你可以使用 # 运算符获取数组的“长度”。

> t = {"a", "b", "c"}
> = #t
3

# 运算符不会计算表中的所有项目 (!)。相反,它会找到最后一个整数(非小数)键。由于它的实现方式,如果表中所有整数键不连续,则其结果是未定义的。这就是为什么它不应该用于用作稀疏数组的表[2])。

有两种方法可以将项目添加到数组的末尾。

> t = {}
> table.insert(t, 123)
> t[#t+1] = 456
> = t[1]
123
> = t[2]
456

table.insert 接受一个可选的索引参数,用于插入到数组的中间。它会将任何其他高于索引的整数键向上移动。

> t = {"a", "c"}
> table.insert(t, 2, "b")
> = t[1], t[2], t[3]
a b c

table.remove 从数组中删除一个项目,将任何剩余的整数键向下移动。

> t = {"a", "b", "c"}
> table.remove(t, 2)
> = t[1], t[2]
a c

要遍历数组,请使用 ipairs。与 pairs 不同,它只提供从 1 开始的连续整数键。它保证它们的顺序。使用 pairs,数字键不一定按正确的顺序给出!

> t = {"a", "b", "c"}
> for i, v in ipairs(t) do print(i, v) end
1       a
2       b
3       c

要将字符串数组连接在一起,可以使用 table.concat。它接受一个可选的分隔符、开始和结束参数。这里我们只使用分隔符。

> t = {"a", "b", "c"}
> = table.concat(t, ";")
a;b;c

有关所有 table.* 函数及其完整文档的列表,请参见 [[3]]。

表值是引用。

当你将表传递给函数或将其存储在新的变量中时,等等,不会创建该表的新的副本。表在这些情况下不会像数字一样。相反,变量或函数会成为对原始表的引用。这很像 C 语言中的指针。例如

> t = {}
> u = t
> u.foo = "bar"
> = t.foo
bar
> function f(x) x[1] = 2 end
> f(t)
> = u[1]
2

当对它们的最后一个引用消失后,表会由垃圾收集器从内存中释放。但是,这并不总是立即发生。垃圾收集器被设计为即使表(直接或间接)包含对自身的引用也能正常工作。

要记住的一件事是,表比较按引用进行。使用 == 比较表将返回 false,即使两个表具有相同的内容。它们实际上必须是对同一个表的引用。

最后,如果你想复制一个表格,你必须手动操作。Lua 没有提供标准函数来复制表格,主要是因为复制表格的方式有很多种。

表格作为无序集合

通常,Lua 的新手会创建一个数组来存储一组对象,即使顺序并不重要。这样做的问题是删除操作很慢,因为计算机需要将其他项目向下移动。检查项目是否在数组中也很慢,同样是因为计算机必须遍历所有项目。

可以通过将项目存储在键中并将值设置为一个虚拟值(如 true)来解决这个问题。这样做将帮助你像使用无序集合一样使用表格,实现快速插入、删除和查找。

主要区别在于没有简单的方法来获取计数(你必须使用循环),并且你不能在集合中存储相同的项目两次。

因此,如果你需要存储一组项目,最好考虑集合和数组,看看哪种最适合你的情况。

local items = {}

-- add some items to the set
items["foo"] = true
items[123] = true

-- is "foo" in the set?
if items["foo"] then
  -- do stuff
end

-- remove item from the set
items[123] = nil

最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2020 年 9 月 23 日下午 8:38 GMT (差异)