table 庫是由一些輔助函數(shù)構成的,這些函數(shù)將 table 作為數(shù)組來操作。
在 Lua 中,數(shù)組下標從 1 開始計數(shù)。
官方解釋:Lua lists have a base index of 1 because it was thought to be most friendly for non-programmers, as it makes indices correspond to ordinal element positions.
確實,對于我們數(shù)數(shù)來說,總是從 1 開始數(shù)的,而從 0 開始對于描述偏移量這樣的東西有利。而 Lua 最初設計是一種類似 XML 的數(shù)據(jù)描述語言,所以索引(index)反應的是數(shù)據(jù)在里面的位置,而不是偏移量。
在初始化一個數(shù)組的時候,若不顯式地用鍵值對方式賦值,則會默認用數(shù)字作為下標,從 1 開始。由于在 Lua 內部實際采用哈希表和數(shù)組分別保存鍵值對、普通值,所以不推薦混合使用這兩種賦值方式。
local color={first="red", "blue", third="green", "yellow"}
print(color["first"]) --> output: red
print(color[1]) --> output: blue
print(color["third"]) --> output: green
print(color[2]) --> output: yellow
print(color[3]) --> output: nil
從其他語言過來的開發(fā)者會覺得比較坑的一點是,當我們把 table 當作?;蛘哧犃惺褂玫臅r候,容易犯錯,追加到 table 的末尾用的是 s[#s+1] = something
,而不是 s[#s] = something
,而且如果這個 something 是一個 nil 的話,會導致這一次壓棧(或者入隊列)沒有存入任何東西,#s 的值沒有變。如果 s = { 1, 2, 3, 4, 5, 6 }
,你令 s[4] = nil
,#s 會令你“匪夷所思”地變成 3。
取長度操作符寫作一元操作 #。字符串的長度是它的字節(jié)數(shù)(就是以一個字符一個字節(jié)計算的字符串長度)。
對于常規(guī)的數(shù)組,里面從 1 到 n 放著一些非空的值的時候,它的長度就精確的為 n,即最后一個值的下標。如果數(shù)組有一個“空洞”(就是說,nil 值被夾在非空值之間),那么 #t 可能是指向任何一個是 nil 值的前一個位置的下標(就是說,任何一個 nil 值都有可能被當成數(shù)組的結束)。這也就說明對于有“空洞”的情況,table 的長度存在一定的 不可確定性。
local tblTest1 = { 1, a = 2, 3 }
print("Test1 " .. table.getn(tblTest1))
local tblTest2 = { 1, nil }
print("Test2 " .. table.getn(tblTest2))
local tblTest3 = { 1, nil, 2 }
print("Test3 " .. table.getn(tblTest3))
local tblTest4 = { 1, nil, 2, nil }
print("Test4 " .. table.getn(tblTest4))
local tblTest5 = { 1, nil, 2, nil, 3, nil }
print("Test5 " .. table.getn(tblTest5))
local tblTest6 = { 1, nil, 2, nil, 3, nil, 4, nil }
print("Test6 " .. table.getn(tblTest6))
我們使用 Lua 5.1 和 LuaJIT 2.1 分別執(zhí)行這個用例,結果如下:
# lua test.lua
Test1 2
Test2 1
Test3 3
Test4 1
Test5 3
Test6 1
# luajit test.lua
Test1 2
Test2 1
Test3 1
Test4 1
Test5 1
Test6 1
這一段的輸出結果,就是這么 匪夷所思。請問,你以后還敢在 Lua 的 table 中用 nil 值嗎?如果你繼續(xù)往后面加 nil,你可能會發(fā)現(xiàn)點什么。你可能認為你發(fā)現(xiàn)的是個規(guī)律。但是,你千萬不要認為這是個規(guī)律,因為這是錯誤的。
不要在 Lua 的 table 中使用 nil 值,如果一個元素要刪除,直接 remove,不要用 nil 去代替。
對于元素是 string 或者 number 類型的表 table,返回 table[i]..sep..table[i+1] ··· sep..table[j]
連接成的字符串。填充字符串 sep 默認為空白字符串。起始索引位置 i 默認為 1,結束索引位置 j 默認是 table 的長度。如果 i 大于 j,返回一個空字符串。
示例代碼
local a = {1, 3, 5, "hello" }
print(table.concat(a)) -- output: 135hello
print(table.concat(a, "|")) -- output: 1|3|5|hello
print(table.concat(a, " ", 4, 2)) -- output:
print(table.concat(a, " ", 2, 4)) -- output: 3 5 hello
在(數(shù)組型)表 table 的 pos 索引位置插入 value,其它元素向后移動到空的地方。pos 的默認值是表的長度加一,即默認是插在表的最后。
示例代碼
local a = {1, 8} --a[1] = 1,a[2] = 8
table.insert(a, 1, 3) --在表索引為1處插入3
print(a[1], a[2], a[3])
table.insert(a, 10) --在表的最后插入10
print(a[1], a[2], a[3], a[4])
-->output
3 1 8
3 1 8 10
返回(數(shù)組型)表 table 的最大索引編號;如果此表沒有正的索引編號,返回 0。
當長度省略時,此函數(shù)通常需要 O(n)
的時間復雜度來計算 table 的末尾。因此用這個函數(shù)省略索引位置的調用形式來作 table 元素的末尾追加,是高代價操作。
示例代碼
local a = {}
a[-1] = 10
print(table.maxn(a))
a[5] = 10
print(table.maxn(a))
-->output
0
5
此函數(shù)的行為不同于 #
運算符,因為 #
可以返回數(shù)組中任意一個 nil 空洞或最后一個 nil 之前的元素索引。當然,該函數(shù)的開銷相比 #
運算符也會更大一些。
在表 table 中刪除索引為 pos(pos 只能是 number 型)的元素,并返回這個被刪除的元素,它后面所有元素的索引值都會減一。pos 的默認值是表的長度,即默認是刪除表的最后一個元素。
示例代碼
local a = { 1, 2, 3, 4}
print(table.remove(a, 1)) --刪除速索引為1的元素
print(a[1], a[2], a[3], a[4])
print(table.remove(a)) --刪除最后一個元素
print(a[1], a[2], a[3], a[4])
-->output
1
2 3 4 nil
4
2 3 nil nil
按照給定的比較函數(shù) comp 給表 table 排序,也就是從 table[1] 到 table[n],這里 n 表示 table 的長度。 比較函數(shù)有兩個參數(shù),如果希望第一個參數(shù)排在第二個的前面,就應該返回 true,否則返回 false。 如果比較函數(shù) comp 沒有給出,默認從小到大排序。
示例代碼
local function compare(x, y) --從大到小排序
return x > y --如果第一個參數(shù)大于第二個就返回true,否則返回false
end
local a = { 1, 7, 3, 4, 25}
table.sort(a) --默認從小到大排序
print(a[1], a[2], a[3], a[4], a[5])
table.sort(a, compare) --使用比較函數(shù)進行排序
print(a[1], a[2], a[3], a[4], a[5])
-->output
1 3 4 7 25
25 7 4 3 1
LuaJIT 2.1 新增加的 table.new
和 table.clear
函數(shù)是非常有用的。前者主要用來預分配 Lua table 空間,后者主要用來高效的釋放 table 空間,并且它們都是可以被 JIT 編譯的。具體可以參考一下 OpenResty 捆綁的 lua-resty-* 庫,里面有些實例可以作為參考。