表格教程 |
|
表格使用表格构造器创建,表格构造器使用花括号定义,例如 { }
。要定义一个空表格,我们可以执行以下操作。
> t = {} -- construct an empty table and assign it to variable "t" > print(t) table: 0035AE18
要访问表格中与键关联的值,可以使用 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