美思 [Lua] 程式設計教學:使用表 (table)

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

表 (table) 是 Lua 唯一的資料結構,在 Lua 內部的實作上,表帶有雜湊表 (hash table) 和陣列 (array) 兩種資料結構,Lua 會視需求自動呼叫適合的結構。對使用者來說,不需要去區分這些細節,把表當成關聯式陣列 (associative array) 來使用即可。

表有許多的用途,如下:

  • 做為陣列 (array)
  • 做為字典 (dictionary)
  • 用於物件導向程式 (object-oriented programming)
  • 模擬其他資料結構 (data structures)

本文著重前兩者,其他的用途於後文介紹。

以表做為陣列

陣列 (array) 是一種以數字為索引的線性資料結構,在 Lua 中是以表模擬。

以索引取值

我們也可以用數字做為索引 (index) 取值:

-- Create an array.
local arr = {"a", "b", "c", "d", "e"}

-- Retrieve the 3rd element.
assert(arr[3] == "c")

要注意的是,Lua 的陣列從 1 開始取索引,和大部分主流語言不同。

以下的陣列會造成空洞 (holes):

local arr = {}

arr[1] = "a"
arr[2] = "b"
-- arr[3] and arr[4] are nil
arr[5] = "c"
arr[6] = "d"

在 Lua 程式中,陣列的空洞會造成一些意想不到的 bug,應避免。

走訪陣列

使用 for 迴圈搭配 ipairs 函式可走訪陣列:

-- Create an array.
local arr = {"a", "b", "c", "d", "e"}

-- Iterate over the array.
for i, e in ipairs(arr) do
  print(e)
end

也可以用數字為索引來走訪陣列:

-- Create an array.
local arr = {"a", "b", "c", "d", "e"}

-- Iterate over the array.
for i = 1, #arr do
  print(arr[i])
end

取得陣列長度

Lua 用 # (number sign) 取得陣列長度,見下例:

-- Create an array.
local arr = {"a", "b", "c", "d", "e"}

-- Check the length of the array.
assert(#arr == 5)

要注意的是,當陣列後端元素皆為 nil 時,不計入長度,見下例:

local arr = {10, 20, 30, nil, nil}

assert(#arr == 3)

注意此處 arr 的長度是 3 而不是 5

將元素插入陣列

利用 table.insert 可在尾端插入新的元素,見以下實例:

-- Create an array.
local arr = {"a", "b", "c", "d", "e"}

-- Check the length of the array.
assert(#arr == 5)

-- Append an element.
table.insert(arr, "f")

-- Recheck the length of the array.
assert(#arr == 6)
assert(arr[6] == "f")

或是使用 arr[#arr+1] = "f" 也可從尾端插入元素。

除了從尾端插入元素,也可從中間插入元素,見下例:

-- Create an array.
local arr = {"a", "b", "c", "d", "e"}

-- Check the length of the array.
assert(#arr == 5)

-- Insert an element at position 3.
table.insert(arr, 3, "f")

-- Recheck the length of the array.
assert(#arr == 6)
assert(arr[3] == "f")

從陣列中去除元素

使用 table.remove 可以從尾端去除元素,見下例:

-- Create an array.
local arr = {"a", "b", "c", "d", "e"}

-- Check the length of the array.
assert(#arr == 5)

-- Pop an element.
popped = table.remove(arr)

-- Recheck the length of the array.
assert(#arr == 4)
assert(popped == "e")

也可以從中間去除元素,見下例:

-- Create an array.
local arr = {"a", "b", "c", "d", "e"}

-- Check the length of the array.
assert(#arr == 5)

-- Remove an element from position 2.
removed = table.remove(arr, 2)

-- Recheck the length of the array.
assert(#arr == 4)
assert(removed == "b")

做為字典

字典是一種以鍵/值對 (key-value pairs) 為組合的非線性資料結構,以鍵為索引取值。

建立字典

以下實例建立一個字典:

-- Create an dictionary.
local dict = {
  one="eins",
  two="zwei",
  three="drei"
}

-- Retrieve the value with the key.
assert(dict["one"] == "eins")

也可以先建立字典再逐一加入鍵值對:

-- Create an dictionary.
local dict = {}

-- Add some key/value pairs.
dict["one"] = "eins"
dict["two"] = "zwei"
dict["three"] = "drei"

-- Retrieve the value with the key.
assert(dict["one"] == "eins")

走訪字典

可以用 for 迴圈搭配 pairs 函式來走訪字典,見下例:

-- Create an dictionary.
local dict = {one="eins", two="zwei", three="drei"}

-- Iterate over the dictionary.
for k, v in pairs(dict) do
  print(k .. ": " .. v)
end

註:注意 pairs 用來走訪字典,ipairs 用來走訪陣列。

從字典中去除鍵值對

若要去除元素,將其值設為 nil 即可,以下是實例:

-- Create an dictionary.
local dict = {one="eins", two="zwei", three="drei"}

-- Remove an key-value pair.
dict["three"] = nil

-- Retrieve some values.
assert(dict["one"] == "eins")
assert(dict["three"] == nil)
關於作者

身為資訊領域碩士,美思認為開發應用程式的目的是為社會帶來價值。如果在這個過程中該軟體能成為永續經營的項目,那就是開發者和使用者雙贏的局面。

美思喜歡用開源技術來解決各式各樣的問題,但必要時對專有技術也不排斥。閒暇之餘,美思將所學寫成文章,放在這個網站上和大家分享。