同一表中存储的值可以具有不同的类型索引,并可以按需增长以容纳新的元素
> a = {} -- 空的表 > for i = 1, 1000 do a[i] = i * 2 end -- 创建1000个新元素 > a[9] --> 18 > a["x"] = 10 > a["x"] --> 10 > a["y"] --> nil
注意上述代码的最后一行,如同全局变量一样,未经初始化的表元素为 nil
,将 nil
赋值给表元素可以将其删除。这并非巧合,因为 Lua
语言实际上就是使用表来存储全局变量的。
把表当做结构体使用时,可以把索引当成成员名称使用( a.name
等价 于a["name"]
)。因此,可以使用这种更加易读的方式改写前述示例的最后几行:
> a = {} -- 空白表 > a.x = 10 -- 等价于a["x"] = 10 > a.x --> 10 -- 等价于a["x"] > a.y --> nil -- 等价于a["y"]
对 Lua
语言而言,这两种形式是等价却可以自由混用的;不过对于阅读程序的人而言,这两种形式可能代表了不同的意图。形如 a.name
的点分形式清晰地说明了表是被当做结构体使用的,此时表实际上是由固定的、预先定义的键组成的集合;而形如 a["name"]
的字符串索引形式则说明了表可以使用任意字符串作为键,并且出于某种原因我们操作的是指定的键。
初学者常常会混淆 a.x
和 a[x]
。实际上, a.x
代表的是 a["x"]
,即由字符串 "x"
索引的表;而 a[x]
则是指由变量 x
对应的值索引的表,例如:
> a = {} > x = "y" > a[x] = 10 -- 把10放在字段"y"中 > a[x] --> 10 -- 字段"y"的值 > a.x --> nil -- 字段"x"的值(未定义) > a.y --> 10 -- 字段"y"的值
由于可以使用任意类型索引表,所以在索引表时会遇到相等性比较方面的微妙问题。虽然确实都能用数字 0
和字符串 "0"
对同一个表进行所以,但这两个索引的值及其所对应的元素是不同的。同样,字符串 "+1"
、 "01"
和 "1"
指向的也是不同的元素。当不能确定表索引的真实数据类型时,可以使用显式的类型转换:
> i = 10; j = "10"; k = "+10" > a = {} > a[i] = "number key" > a[j] = "string key" > a[k] = "another string key" > a[i] --> number key > a[j] --> string key > a[k] --> another string key > a[tonumber(j)] --> number key > a[tonumber(k)] --> number key
注意
如果不注意这一点,就会很容易在程序中引入诡异的Bug。
整型和浮点型类型的表索引则不存在上述问题。由于 2
和 2.0
的值相等,所以当他们被当做表索引使用时指向的是同一个表元素。
> a = {} > a[2.0] = 10 > a[2.1] = 20 > a[2] --> 10 > a[2.1] --> 20
更准确地说,当被用作表索引时,任何能够被转换为整数的浮点数都会被转换成整型数。例如,当表达式 a[2.0]=10
时,键 2.0
会被转换为 2
。相反,不能被转换为整型数的浮点数则不会发生上述的类型转换。