OpenResty實戰-Lua入門-table庫

OpenResty實戰-Lua入門-table庫

table 庫是由一些輔助函數構成的,這些函數將 table 作為數組來操作。

下標從 1 開始

在 Lua 中,數組下標從 1 開始計數。

官方解釋: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.

確實,對於我們數數來說,總是從 1 開始數的,而從 0 開始對於描述偏移量這樣的東西有利。而 Lua 最初設計是一種類似 XML 的數據描述語言,所以索引(index) 反應的是數據在裡面的位置,而不是偏移量。

在初始化一個數組的時候,若不顯式地用鍵值對方式賦值,則會默認用數字作為下標,從 1 開始。由於在 Lua 內部實際採用哈希表和數組分別保存鍵值對、普通值,所以不推薦混合使用這兩種賦值方式。

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

從其他語言過來的開發者會覺得比較坑的一點是,當我們把 table 當作棧或者隊列使用的時候,容易犯錯,追加到 table 的末尾用的是 s[#s+1] = something ,而不是 s[#s] = something ,而且如果這個 something 是一個 nil 的話,會導致這一次壓棧(或者入隊列) 沒有存入任何東西,#s 的值沒有變。如果 s = { 1, 2, 3, 4, 5, 6 } ,你令 s[4] = nil ,#s會令你“匪夷所思”地變成 3。

table.getn 獲取長度

取長度操作符寫作一元操作 #。字符串的長度是它的字節數(就是以一個字符一個字節計算的字符串長度) 。

對於常規的數組,裡面從 1 到 n 放著一些非空的值的時候,它的長度就精確的為 n,即最後一個值的下標。如果數組有一個“空洞”(就是說,nil 值被夾在非空值之間) ,那麼 #t 可能是指向任何一個是 nil 值的前一個位置的下標(就是說,任何一個 nil 值都有可能被當成數組的結束) 。這也就說明對於有“空洞”的情況,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 分別執行這個用例,結果如下:

# 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 值嗎?如果你繼續往後面加 nil,你可能會發現點什麼。你可能認為你發現的是個規律。但是,你千萬不要認為這是個規律,因為這是錯誤的。

不要在 Lua 的 table 中使用 nil 值,如果一個元素要刪除,直接 remove,不要用 nil 去代替。

table.concat (table [, sep [, i [, j ] ] ])

對於元素是 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

table.insert (table, [pos ,] value)

在(數組型) 表 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

table.maxn (table)

返回(數組型) 表 table 的最大索引編號;如果此表沒有正的索引編號,返回 0。

當長度省略時,此函數通常需要 O(n) 的時間複雜度來計算 table 的末尾。因此用這個函數省略索引位置的調用形式來作 table 元素的末尾追加,是高代價操作。

示例代碼

local a = {}

a[-1] = 10

print(table.maxn(a))

a[5] = 10

print(table.maxn(a))

-->output

0 5

此函數的行為不同於 # 運算符,因為 # 可以返回數組中任意一個 nil 空洞或最後一個 nil 之前的元素索引。當然,該函數的開銷相比 # 運算符也會更大一些。

table.remove (table [, pos])

在表 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

table.sort (table [, comp])

按照給定的比較函數 comp 給表 table 排序,也就是從 table[1] 到 table[n],這裡 n 表示 table的長度。 比較函數有兩個參數,如果希望第一個參數排在第二個的前面,就應該返回 true,否則返回 false。 如果比較函數 comp 沒有給出,默認從小到大排序。

示例代碼

local function compare(x, y) --從大到小排序

return x > y --如果第一個參數大於第二個就返回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) --使用比較函數進行排序

print(a[1], a[2], a[3], a[4], a[5])

-->output

1 3 4 7 25

25 7 4 3 1

table 其他非常有用的函數

LuaJIT 2.1 新增加的 table.new 和 table.clear 函數是非常有用的。前者主要用來預分配Lua table 空間,後者主要用來高效的釋放 table 空間,並且它們都是可以被 JIT 編譯的。具體可以參考一下 OpenResty 捆綁的 lua-resty-* 庫,裡面有些實例可以作為參考。

至此,Lua的Table庫就介紹完了,下一篇將介紹Lua的日期時間函數。

後續計劃內容:

Lua入門+高階

Nginx

OpenResty

LuaRestyRedisLibrary

LuaCjsonLibrary

PostgresNginxModule

LuaNginxModule

LuaRestyDNSLibrary

LuaRestyLock

stream_lua_module

balancer_by_lua

OpenResty 與 SSL

測試

Web服務

火焰圖

OpenResty周邊

零碎知識點


分享到:


相關文章: