第一版是為 Lua 5.0 編寫的。儘管在很大程度上仍然適用於後續版本,但仍有一些不同之處。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買本書,您還可以幫助 支援 Lua 專案。
![]() |
用 Lua 進行程式設計 | ![]() |
第一部分。語言 第 7 章。反覆運算器和一般 for |
反覆運算器是任何允許您反覆運算集合中元素的建構。在 Lua 中,我們通常用函式表示反覆運算器:每次呼叫該函式時,它會傳回集合中的「下一個」元素。
任何反覆運算器都需要在連續呼叫之間保留一些狀態,以便它知道它在哪裡以及如何從那裡繼續。封閉提供了一個絕佳的機制來執行此任務。請記住,封閉是一個函式,它會存取其封閉函式中的其中一個或多個局部變數。這些變數會在連續呼叫封閉時保留其值,讓封閉記住它在遍歷中的位置。當然,要建立一個新的封閉,我們也必須建立它的外部局部變數。因此,封閉建構通常涉及兩個函式:封閉本身;以及一個工廠,也就是建立封閉的函式。
舉一個簡單的例子,讓我們為一個清單撰寫一個簡單的反覆運算器。與 ipairs
不同,此反覆運算器不會傳回每個元素的索引,只會傳回值
function list_iter (t) local i = 0 local n = table.getn(t) return function () i = i + 1 if i <= n then return t[i] end end end在此範例中,
list_iter
是工廠。每次我們呼叫它時,它會建立一個新的封閉(反覆運算器本身)。該封閉會在其外部變數(t
、i
和 n
)中保留其狀態,以便每次我們呼叫它時,它會傳回清單 t
中的下一筆值。當清單中沒有更多值時,反覆運算器會傳回 nil。
我們可以使用此類反覆運算器搭配 while
t = {10, 20, 30} iter = list_iter(t) -- creates the iterator while true do local element = iter() -- calls the iterator if element == nil then break end print(element) end不過,使用一般 for 會比較容易。畢竟,它就是為這種反覆運算而設計的
t = {10, 20, 30} for element in list_iter(t) do print(element) end一般 for 會處理反覆運算迴圈中的所有簿記:它會呼叫反覆運算器工廠;在內部保留反覆運算器函式,因此我們不需要
iter
變數;在每次新的反覆運算時呼叫反覆運算器;當反覆運算器傳回 nil 時停止迴圈。(稍後我們會看到一般 for 實際上會執行更多操作。)
作為一個更進階的範例,我們將撰寫一個反覆運算器來遍歷目前輸入檔案中的所有字詞。若要執行此遍歷,我們需要保留兩個值:目前行數和我們在該行中的位置。有了這些資料,我們永遠可以產生下一個字詞。為了保留這些資料,我們使用兩個外部局部變數,line
和 pos
function allwords () local line = io.read() -- current line local pos = 1 -- current position in the line return function () -- iterator function while line do -- repeat while there are lines local s, e = string.find(line, "%w+", pos) if s then -- found a word? pos = e + 1 -- next position is after this word return string.sub(line, s, e) -- return the word else line = io.read() -- word not found; try next line pos = 1 -- restart from first position end end return nil -- no more lines: end of traversal end end迭代器函數的主要部分是呼叫
string.find
。此呼叫會從目前位置開始,在目前行中搜尋一個字詞。它使用模式 '%w+
' 來描述「字詞」,這個模式會比對一個或多個字母數字字元。如果找到字詞,函數會將目前位置更新為字詞後的第一個字元,並傳回該字詞。(string.sub
呼叫會從 line
中萃取一個子字串,位置介於給定的位置之間)。否則,迭代器會讀取新的一行,並重複搜尋。如果沒有更多行,它會傳回 nil 來表示迭代結束。
儘管 allwords
很複雜,但它的用法很簡單
for word in allwords() do print(word) end這是迭代器常見的情況:它們可能很難撰寫,但很容易使用。這不是什麼大問題;通常,使用 Lua 進行編程的最終使用者不會定義迭代器,而只會使用應用程式提供的迭代器。
版權所有 © 2003–2004 Roberto Ierusalimschy。保留所有權利。 | ![]() |