資料表教學 |
|
使用大括弧定義的表格建構子建立資料表,例如: { }
。要定義一個空資料表,我們可以執行以下操作。
> t = {} -- construct an empty table and assign it to variable "t" > print(t) table: 0035AE18
要存取資料表中與金鑰關聯的值,可以使用 table[key]
語法
> t = {} > t["foo"] = 123 -- assign the value 123 to the key "foo" in the table > t[3] = "bar" -- assign the value "bar" to the key 3 in the table > = t["foo"] 123 > = t[3] bar
如果沒有與金鑰關聯的值,這並非錯誤,結果將會是 nil
> t = {} > = t["foo"] nil
你可以透過將 nil 指定給值來從資料表中刪除一個金鑰/值對。
> t["foo"] = nil
任何值都可以用作金鑰(不只是數字和字串),只要確保它不是 nil
或 NaN(非數字)即可
> t = {} > k = {} > f = function () end > t[k] = 123 > t[f] = 456 > = t[k] 123 > = t[f] 456 > t[nil] = 123 stdin:1: table index is nil stack traceback: stdin:1: in main chunk [C]: in ? > t[0/0] = 123 stdin:1: table index is NaN stack traceback: stdin:1: in main chunk [C]: in ?
但是使用字串常數作為金鑰非常普遍,因此有一個特殊的捷徑語法
> t = {} > t.foo = 123 -- same as t["foo"] (but not t[foo], which would use the variable foo as the key) > = t.foo 123 > = t["foo"] 123
你也可以直接在 {} 語法裡面新增金鑰/值關聯。
> t = {["foo"] = "bar", [123] = 456} > = t.foo bar > = t[123] 456
還有一個適用於 {} 中字串金鑰的語法捷徑,只要字串符合與 .
語法相同的規則即可
> t = {foo = "bar"} -- same as ["foo"]="bar" (but not [foo]="bar" , that would use the variable foo) > = t["foo"] bar
要迴圈遍歷資料表中的所有金鑰/值對,請使用 pairs
迭代器
> t = {foo = "bar", [123] = 456} > for key,value in pairs(t) do print(key,value) end foo bar 123 456
pairs
迴圈的順序是不確定的。即使你是在新增另一個項目後才新增一個項目,也不表示它們在 pairs
中的順序也會如此。在 pairs
迴圈內,重新指派現有金鑰或刪除金鑰(透過將 nil 指定給它們)是安全的,但不要新增新的金鑰(先前具有 nil 值)。
首先,記住資料表仍然只是金鑰/值容器,因為 Lua 實際上並沒有陣列類型。但資料表可以被當作陣列來處理,此處有說明
資料表建構子可以包含以逗號分隔的物件清單來建立「陣列」
> t = {"a", "b", "c"} > = t[1] a > = t[3] c
> t = {[1]="a", [2]="b", [3]="c"} > = t[1] a > = t[3] c
你也可以將陣列語法與一般的 key=value 語法混合使用
> t = {"a", "b", [123]="foo", "c", name="bar", "d", "e"} > for k,v in pairs(t) do print(k,v) end 1 a 2 b 3 c 4 d 5 e 123 foo name bar
第一個索引是數字一,這與大多數從數字零開始的其他語言不同。選擇這個數字的原因是因為它通常更直觀。它也被選為金鑰,而不是開始的偏移量。大多數語言實作實際的陣列類型。
你可以使用 #
運算子來取得陣列的「長度」
> t = {"a", "b", "c"} > = #t 3
#
算符不會計算表格中所有項目(!)。而是會找出最後一個整數(非分數)鍵。由於其實作方式,如果表格中的所有整數鍵不是連續的,其結果便未定義。這就是為什麼不應將其用於當作稀疏陣列所用的表格[2]。
有兩種方式可將項目新增到陣列的尾端
> t = {}
> table.insert(t, 123)
> t[#t+1] = 456
> = t[1]
123
> = t[2]
456
table.insert
採用一個選用的索引參數來插入至陣列的中央。它會向上移動索引上方的任何其他整數鍵
> t = {"a", "c"} > table.insert(t, 2, "b") > = t[1], t[2], t[3] a b c
table.remove
移掉陣列中的項目,向下移動任何尚存的整數鍵
> t = {"a", "b", "c"} > table.remove(t, 2) > = t[1], t[2] a c
若要迴圈陣列,請使用 ipairs
。與對齊(pairs)不同,它僅提供連續的整數鍵,且起始於 1。它保證順序。使用對齊(pairs)時,數字鍵不一定要以正確順序提供!
> t = {"a", "b", "c"} > for i, v in ipairs(t) do print(i, v) end 1 a 2 b 3 c
若要連接一組字串,則使用 table.concat
。它採用選用的分隔符號、開頭及結尾參數。此處我們僅使用分隔符號
> t = {"a", "b", "c"} > = table.concat(t, ";") a;b;c
若要取得所有 table.* 函數清單及其完整的文件,請參閱 [[3]]
當您傳遞一個表格給函數,或將其儲存在新的變數中等等動作時,並不會建立該表格的新拷貝。這種狀況時,表格並不像數字那樣作用。相反地,變數或函數會變成對原始表格的參考。這很像 C 語言中的指標。例如
> t = {} > u = t > u.foo = "bar" > = t.foo bar > function f(x) x[1] = 2 end > f(t) > = u[1] 2
表格會在對其的最後一次參考消失後,由垃圾回收器從記憶體中移除。然而,這並非總會立即發生。垃圾回收器設計用於正確地運作,即使一個表格(直接或間接)包含對本身的參考。也將發生。
還有一件相關的事情要記住:表格比較是透過參考來運作的。使用 ==
比較表格時,即使兩個表格有相同的內容,仍會傳回 false
。它們必須實際上是對相同表格的參考。
最後,如果您要複製一張表格,必須要手動執行。Lua 沒有提供標準的函數,主要是因為有許多不同的方式可以複製一張表格。
經常有一些初學者會建立一個陣列來存放一組物件,即使不需要順序也是如此。這樣做會出現一個問題,那就是移除的動作比較慢,因為電腦必須向下移動其他項目。檢查陣列中是否有一個項目,這個動作也很慢,因為電腦必須迴圈處理所有項目。
透過將項目儲存在鍵中,並將值設定為虛擬值(例如 true
),即可解決這個問題。這樣做將能幫助您將表格用成一個未排序的集合,可以快速插入、移除及查詢。
主要的差異點是,沒有簡單的方法來取得計數(您必須使用迴圈),而且您無法在集合中儲存同一項兩次。
所以如果您需要儲存一組項目,最好同時考慮集合及陣列,選擇最適合您現在情況的
local items = {} -- add some items to the set items["foo"] = true items[123] = true -- is "foo" in the set? if items["foo"] then -- do stuff end -- remove item from the set items[123] = nil