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

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個值:

  1. 一個迭代器函數
  2. 一個恆定狀態
  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]


pairsipairs的區別
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)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章