概念
是Lua语言最主要和强大的数据结构
可以表示:数组、集合、记录和其它数据结构
是一种辅助数组,不仅可以使用数值作为索引,也可以使用字符串或其它任意类型的值作为索引
表是一种动态分配对象,程序只能操作指向表的引言
例
a = {} --创建一个表
k = "x"
a[k] = 10 --新元素,键(key)是"x",值(value)是10 a={x= 10}
a[20] = "great" --新元素,键是20,值是"great" a={x= 10, 20= "great"}
a["x"] --> 10
k = 20
a[k] --> "great" a={x= 10, 20= "great"}
a["x"] = a["x"] + 1 --增加元素"x"的值 a={x= 11, 20= "great"}
a["x"] --> 11
表永远是匿名的,表本身和保存表的变量之间没有固定的关系
a = {}
a["x"] = 10
b = a -- 'b'和'a'引用同一张表
b["x"] --> 10
b["x"] = 20
a["x"] --> 20
a = nil --只有'b'仍然指向表
b = nil --没有指向表的引用了
对于一个表而言,当程序中不再有指向它的引用时,垃圾收集器会最终删除这个表并重用其占用的内存。
表索引
作为数组使用
同一个表中存储的值可以具有不同的类型索引,并可以按需增长以容纳新的元素:
a={} --空的表
--创建1000个新元素 Lua索引是从1开始的
for i = 1, 1000 do --a = {2, 4, 6, 8, 10, 12, 14, 16, 18....}
a[i] =i*2
end
a[9] --> 19
a["x"] = 10
a["x"] --> 10
a["y"] --> nil 未初始化默认为nil
作为结构体使用
当把表当作结构体使用时,可以把索引当作成员名称使用(a.name
等价于a["name"]
)。
a = {} --空白表
a.x = 10 --等价于a["x"] =10
a.x -->10 等价于a["x"]
a.y -->nil 等价于a["y"]
两者可通用
a = {0}
x = "y"
a[x] =10 --把10放在字段"y"中 a={y=10}
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={10="number key", "10" = "string key", "+10" = "another string key"}
a[i] -->数值类型的键
a[j] -->字符串类型的键
a[k] -->另一个字符串类型的键
a[tonumber(j)] -->数值类型的键
a[tonumber(k)] -->数值类型的键
整型和浮点型不存在上述问题
a ={}
a[2.0] = 10
a[2.1] = 20
a[2] -->10
a[2.1] -->20
表构造器
表构造器是用来创建和初始化表的表达式。
方法一
days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
days[4] -->Wednesday
方法二
a = {x = 10, y = 20} --key值初始化必须是变量 即 a={10=10, "x" = 20} 不允许,但可以后面设置a[10] = 10
--等价于
a={}
a.x = 10
a.y = 20
两种方法都可以随时添加和删除元素
w = {x = 0, y = 0, label = "console"}
x = {math.sin(0), math.sin(1), math.sin(2)}
w[1] = "another field" --把键1增加到表'w'中 即w = {x = 0, y = 0, label = "console", 1 = "another field"}
x.f = w --把键"f"增加到表'x'中 即x = {math.sin(0), math.sin(1), math.sin(2), f = w}
print(w["x"]) -->0
print(w[1]) -->another field
print(x.f[1]) -->another field
w.x = nil --删除字段"x"
在同一个构造器中,可以混用记录式和列表式写法:
polyline = {color="blue", thickness=2, npoints=4,
{x=0,y=0}, -- polyline[1]
{x=-10,y=0}, -- polyline[2]
{x=-10,y=1}, -- polyline[3]
{x=0, y=1} -- polyline[4]
}
print(polyline[2].x) -->-10
print(polyline[4].y) -->1
可以使用方括号括起来得到表达式显式地指定每一个索引
opnames = {["+"] = "add" , ["-"]= "sub", ["*"] = "mul",["/"] = "div"}
i = 20; s = "_"
a = {[i+0] = s, [i+1] = s..s, [i+2]= s..s..s} --a={[20]="-", [21]="--", [22]="---"}
print(opnames[s]) -->sub
print(a[22]) -->---
{x = 0, y = 0}
--等价于
{["x"]=0, ["y"] = 0}
{"r", "g", "b"}
--等价于
{[1]= "r", [2]= "g", [3] = "b"}
数组、列表和序列
数组或列表
数组和列表只需要使用整型作为索引的表即可。同时,也不需要预先声明表的大小,只需要直接初始化我们需要的元素即可:
这样就可以使用#
来查看长度
a = {}
for i = 1,10 do
a[i] = io.read()
end
序列
所有元素都不为nil的数组称为序列
a = {1, 2, 3, 4, 5} --可以为序列
a[2] = nil --这时就不能称为序列 a={1, nil, 3, 4, 5}
当数组不是序列时,#
就不可靠,这时需要显示保存数组长度,可用table.pack
来判断是否有nil
遍历表
使用pairs
迭代器遍历表中地键值对
t = {10,print, x = 12, k = "hi "}
for k, v in pairs(t) do
print(k,v)
end
-->1 10
-->k hi
-->2 function: 8x420610
-->x 12
遍历顺序是随机的,每次不相同
也可使用数值型for循环,顺序是指定的
t = {10,print,12,"hi"}
for k = 1, #t do
print(k,t[k])
end
-->1 10
-->2 function: 0x420610
-->3 12
-->4 hi
表标准库
插入
函数table.insert
:向序列的指定位置插人二个元素,其他元素依次后移。不指定位置,默认从末尾插入
例如:t={10, 20, 30},调用table.insert(t, 1, 15)后变成{15, 10, 20, 30}
删除
函数table.remove
:删除并返回序列指定位置的元素,然后将其后的元素向前移动填充删除元素后造成的空洞。如果在调用该函数时不指定位置,该函数会删除序列的最后一个元素
借助两函数,可以实现栈、队列和双端队列
移动
函数table.move
:可以将元素移动到指定的位置
如:table.move(a,f,e,t) 将表a中从索引f到e的元素(包含索引f和索引e对应的元素本身)移动到位置t上