深入解讀Lua中迭代器與泛型for的使用

2022-09-21 02:09:10 字數 3498 閱讀 7690

泛型for原理

迭代器是一種可以遍歷集合中所有元素的機制,在lua中通常將迭代器表示為函式,每呼叫一次函式,就返回集合中「下乙個」元素。每個迭代器都需要在每次成功呼叫之間保持一些狀態,這樣才能知道它所在的位置及如何步進到下乙個位置,closure就可以完成此項工作。下面的示例是列表的乙個簡單的迭代器:

function values(t)

local i = 0

return function() i = i + 1; return t[i] end

end迴圈呼叫:

t =

iter = values(t)

while true do

local el = iter()

if el == nil then break end

ardntgprint(el)

end泛型for呼叫

for el in values(t) do print(el) end

泛型for為一次迭代迴圈做了所有的簿記工作。它在內部儲存了迭代器函式,並在每次迭代時呼叫迭代器,在迭代器返回nil時結束迴圈。實際上泛型for儲存了3個值:迭代器函式f、恆定狀態s、控制變數a。for做的第一件事就是對in後面的表示式求值,並返回3個值供for儲存;接著for會以s和a來呼叫f。在迴圈過程中控制變數的值依次為a1 = f(s, a0),a2 = f(s, a1),依次類推,直至ai為nil結束迴圈。

先看一段**

for element in list_iter(t) do

print(element)

end在不往下看之前,我們可以先試圖根據我們已有的知識結構去理解這段**。如果這樣,list_iter(t)應該返回乙個類似集合的東西,而我們已經知道實際上只返回了乙個匿名函式,也就是迭代器。當然,每次呼叫迭代器都可以得到乙個元素,迭代器的所有的結果倒是可以看成乙個集合。因素齊了,我們需要乙個邏輯上的解釋,這個邏輯就是 泛型for的語義。

先看文法規定:

for 程式設計客棧in do

end

整個過程是這樣的:

首先,初始化,計算 in 後面表示式的值,表示式應該返回 泛型for 需要的三個值:迭代函式、狀態常量、控制變數;與多值賦值一樣,如果表示式返回的結果個數不足三個會自

動用nil 補足,多出部分會被忽略。

第二,將狀態常量和控制變數作為引數呼叫迭代函式(注意:對於 for 結構來說,狀態常量沒有用處,僅僅在初始化時獲取他的值並傳遞給迭代函式)。

第三,將迭代函式返回的值賦給變數列表。

第四,如果返回的第乙個值為 nil 迴圈結束,否則執行迴圈體。

第五,回到第二步再次呼叫迭代函式。

更具體地說:

for var_1, ..., var_n in do block end

等價於do

local _f, _s, _var = explist

while true do

local var_1, ... , var_n = _f(_s, _var)

_var = var_1

if _var == nil then break end

block

end

end泛型 for 在自己內部儲存三個值:迭代函式、狀態常量、控制變數。

迭代器的狀態

無狀態的迭代器本身不儲存任何狀態,for迴圈只會用恆定狀態和控制變數來呼叫迭代器函式。這類迭代器典型例子就是ipairs,下面是ipairs的lua實現:

local function iter(s, i)

i = i + 1

local v = s[i]

if v then return i, v end

endfunction ipairs(s)

return iter, s, 0

end當for迴圈呼叫ipairs(list)時,會獲得3個值,然後lua呼叫iter(liswww.cppcns.comt, 0)得到list, list[1],呼叫iter(list, 1)得到list, list[2],知道得到乙個nil為止。

雖然泛型for只提供乙個恆定狀態和乙個控制變數用於狀態的儲存,但有時需要儲存許多其他狀態。這時可以用closure來儲存,或者將所需的狀態打包為乙個table,並儲存在恆定狀態中。

閉包、迭代器和泛型for

到現在,lua為我們準備了三塊積木:閉包、泛型for和迭代器。乙個迴圈,我們可以利用閉包+迭代器,也可以使用泛型for+迭代器。那我們該怎麼取捨呢?lua也給出了建

議。function iter (a, i)

i = i + 1

local v = a[i]

if v then

return i, v

end

end

function ipairs (a)

return iter, a, 0

end

for i, v in ipairs(a) do

print(i, v)

end這種情況是lua最推薦的,迭代器不依賴upvalue,不產生閉包,狀態常量和控制變數借助泛型for儲存,通過迭代器的引數傳遞給了迭代器。

再給乙個書中的例子:

local iterator -- to be defined later

function allwords()

local state =

return iterator, state

end

function iterator (state)

while state.line do -- repeat while there are lines

-- search for next word

local s, e = string.find(state.line, "%w+", state.pos)

if s then -- found a word?

-- update next position (after this word)

state.pos = e + 1

return string.sub(state.line, s, e)

else -- word not found

state.line = io.read() -- try next line...

state.pos = 1 -- ... from first position

end

end

return nil -- no more lines: end loop

end這樣好不好呢,lua給的答案是否定的。書中有一段話說得很清楚:

我們應該盡可能的寫無狀態的迭代器,因為這樣迴圈的時候由for 程式設計客棧來儲存狀態,不需要建立物件花費的代價小;如果不能用無狀態的迭代器實現,應盡可能使用閉包;盡可能不

要使用table 這種方式,因為建立閉包的代價要比建立table 小,另外lua 處理閉包要比處理table 速度快些。

本文標題: 深入解讀lua中迭代器與泛型for的使用

本文位址:

Lua學習(七) 迭代器和泛型for

array for key,value in ipairs array doprint key,value end 上面的示例使用由lua中提供的預設ipairs迭代函式。function square iteratormaxcount,currentnumber if currentnumbere...

Lua入門教程 6 迭代器與泛型for

所謂迭代器就是一種可以遍歷一種集合中所有元素的機制。每個迭代器都需要在每次成功呼叫之間儲存一些狀態,這樣才知道下一步進行到何處,而closure則為這一任務提供了很好的支援。function value t local i 0 return function i i 1 return t i end...

Lua知識點三 迭代器與泛型for

迭代器是一種支援指標型別的結構,它可以遍歷集合的每乙個元素。迭代器需要保留上一次成功呼叫的狀態和下一次成功呼叫的狀態,也就是他知道來自於 和將要前往 閉包提供的機制可以很容易實現這個任務。記住 閉包是乙個內部函式,它可以訪問乙個或者多個外部函式的外部區域性變數。每次閉包的成功呼叫後這些外部區域性變數...