0x06迭代器與泛型for
所謂迭代器就是一種可以遍歷一種集合中所有元素的機制。
迭代器與Closure
每個迭代器都需要在每次成功調用之間保存一些狀態,這樣才知道下一步進行到何處,而Closure
則爲這一任務提供了很好的支持。
function value (t)
local i = 0
return function ()
i = i + 1; return t[i]
end
end
value()在調用時會創建一個Closure
,其中的i保存着迭代的索引值,每調用一次會加一
,直到最後一個元素,之後將會返回nil
t = {20, 30, 40}
for element in value(t) do
print(element)
end
a.泛型for
泛型for
在循環過程內部保存了迭代器函數。實際上保存着3個值:
- 一個迭代器函數
- 一個恆定狀態
- 一個控制變量
泛型for的語法:
for <var-list> in <exp-list> do
<body>
end
<var-list>
是一個或多個變量名的列表,以逗號分隔開
<exp-list>
是一個或多個表達式的列表,以逗號分隔開
變量列表的第一個元素稱爲“控制變量”。循環過程中決不會爲nil,因爲當其爲nil時循環就已經結束了。for做的第一件事情就是對in後面的表達式進行取值,將會返回3個值給for保存。初始化步驟後,for會以恆定狀態和控制變量來調用迭代器函數。然後for將迭代器函數返回值賦予變量列表中的變量。若第一個返回值爲空則停止循環。
b.無狀態的迭代器
一種不保存任何狀態的迭代器 (可以在多個循環中使用他而不會有新的Closure開銷
這樣迭代器的典型例子就是ipairs
a = {"one", "two", "three"}
for i,v in ipairs(a) do
print(i, v)
end
下面是ipairs的實現
local function iter (a, i)
i = i + 1
local v = a[i]
if v then
return i,v
end
function ipairs (a)
return iter, a, 0
end
當Lua調用for循環中的ipairs(a)時,他將獲得迭代函數,恆定狀態a,控制變量的初始值0。Lua調用iter(a,0),得到1,a[1] 繼續調用iter(a,2),獲得2,a[2]
pairs
與ipairs
的區別
pairs的迭代器函數是Lua中的一個基本函數next
c.具有複雜狀態的迭代器
迭代器需要保存許多狀態,使用Closoure可以將需要的狀態保存在恆定狀態中
範例代碼:
local iterator
function allwords()
local state = {line = io.read, pos = 1}
return iterator, state
end
function iterator (state)
while state.line do --若爲有效行的執行內容就進入循環
--搜索下一個單詞
local s,e = string.find(state.line, "%w+", state.pos)
if s then --找到了一個單詞
--更新下一個位置
state.pos = e + 1
return string.sub(state.line, s, e)
else --沒有找到單詞
state.line = io.read() --讀取下一行
state.pos = 1 --從第一個位置開始
end
end
return nil
end
真正的迭代器
迭代器並沒有做實際的迭代,真正做迭代的是for循環。而迭代器只是每次迭代提供一些成功後的返回值。還有一種創建迭代器的方式:在迭代器中做實際的迭代操作
可以重寫allwords()
函數
function allwords (f)
for line in io.lines() do
for word in string.gmatch(line, "%w+") do
f(word)
end
end
end
使用這個迭代器時,需要傳入一個描述循環體的函數。如果要打印每個單詞,那麼可以使用print: allwords(print)