表格教程 |
|
表格使用表格构造器创建,表格构造器使用花括号定义,例如 { } 。要定义一个空表格,我们可以执行以下操作。
> 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