表类型实现了关联数组。关联数组是这样一类数组,它可以用数值、字符串或者其他被语言许可得值作为索引,除了空值以外。另外,表没有固定尺寸,你可以动态增加元素。表是主要的,实际上,也是唯一的 Lua 数据结构,其功能非常强大。对于表,我们可以用一种简单、统一且有效的方式来表示普通的数组、符号表、集合、记录、队列以及其他数据结构。 Lua 也使用表来表示 Lua 包,当我们写 read,它的意思是 io 库里的 read 项。在 Lua 中,意为“io 表中索引为 read 的项”。 Lua 中的表既非值也不是变量,而是对象。如果你熟悉 Java 或者 Scheme 中的数组,那么你应该明白它的确切意义。但如果你只知道 C 或者 Pascal 中的数组,那么你可能还需要更进一步地了解它。你可以认为 Lua 表是一个动态的对象,而你只需要在程序中只是通过引用或者指针的方式来操纵它。而实际上,这个对象的背后并没不存在任何拷贝或新创建的表。此外,你不需要在使用之前声明一个表,实际上,你也无法声明一个表。表是通过构造表达式来创建的,最简单的创建方式即使用“{}”:
a = {} -- 创建一个table,并将它的引用储存到a
k = "x"
a[k] = 10 -- 新条目, key = "x" , value = 10
a[20] = "great" -- 新条目, key = 20 , value = "great"
print(a["x"]) --> 10
k = 20
print(a[k]) --> "great"
a["x"] = a["x"] + 1 -- 递增条目 "x"
print(a["x"]) --> 11
Lua 表总是“匿名”的:一个表变量和表本身之间不存在固定的联系:
a = {}
a["x"] = 10
b = a -- b与a引用了同一个table
print(b["x"]) --> 10
b["x"] = 20
print(a["x"]) --> 20
a = nil -- 现在只有b还在引用table
b = nil -- 再也没有对 table 的引用了
当程序中的表不再被引用, Lua 的内存管理机制最终会删除表并释放表所占用的内存空间。
表可以存储不同类型索引的值,并根据需要在尺寸上增长,以便适应新添加的项。
a = {} -- 空的 table
-- 创建 1000 新条目
for i = 1, 1000 do
a[i] = i * 2
end
print(a[9]) --> 18
a["x"] = 10
print(a["x"]) --> 10
print(a["y"]) --> nil
注意上述最后一行:就像全局变量那样,未经初始化的表域,其值为空值,同样,你也可以将一个
表域赋成空值来删除这个域。这并不是一个巧合,因为对于全局变量, Lua 也同样使用一个普通的表来
存储它们。更多相关信息请参考第十四章。你可以用表域的名称作为一个索引,来表示记录。在 Lua 中可以用 a.name 来便利地表示 a["name"],因此我们可以更简洁地重写上例中的最后几行:
a.x = 10 -- 等同于 a["x"] = 10
print(a.x) -- 等同于 print(a["x"])
print(a.y) -- 等同于 print(a["y"])
在 Lua 中,上述两种方式是等价的,因此可以自由地混合使用。但作为程序读者的普通人而言,每种写法可能代表着不同的意义。
初学者常犯的一种错误是将 a.x 和 a[x]弄混淆了。这里的第一种写法代表了 a["x"],也即,表 a 中由"x"索引的项,而第二种写法表示表 a 中由变量 x 所对应的值索引得项。看下例中的区别:a = {}
x = "y"
a[x] = 10 -- 将10放入字段 "y"
print(a[x]) --> 10 -- 字段 "y" 的值
print(a.x) --> nil -- 字段 "x" (未定义)的值
print(a.y) --> 10 -- 字段 "y"的值
你可以简单地使用整数索引来表示一个普通的数组。你无法声明该数组的尺寸,而仅仅是初始化你所需要的元素。
-- 读取10行内容,并储存到一个table中
a = {}
for i = 1, 10 do
a[i] = read()
end
遍历数组中的元素时,首个未初始化的元素其值为空值,你可以使用此特性来判定数组的末尾。比如你可以用下列代码打印上个例子中读取的数据:
local a = {1,2,3,4,5}
-- 打印所有行
for i, line in a do
print(line)
end
它允许你方便地遍历数组中的各元素,它默认上述有关数组末尾的约定进行工作。既然你可以用任何值来索引数组,那么你也可以用任何数值来索引数组,但在 Lua 中一般用 1 来索引数组的第一个元素(在 C 语言中是 0),因为 Lua 标准库遵循此约定。对于表的索引而言,尽管数值 0 和字符串"0"都能胜任,但是两者是不同的,因此它们索引得位置也是不同的。同样地,字符串"+1"、 "01"和"1"各自索引不同的位置。如果不确定具体的索引类型,可以使用显式的转换:
i = 10; j = "10"; k = "+10"
a = {}
a[i] = "one value"
a[j] = "another value"
a[k] = "yet another value"
print(a[j]) --> another value
print(a[k]) --> yet another value
print(a[tonumber(j)]) --> one value
print(a[tonumber(k)]) --> one value
如果不加注意,你可能会在你的程序中引入难以发现的错误。 |