lua學習之迭代器與泛型for第一篇

迭代器與泛型 for 1

迭代器與 closure

  1. 「迭代器」是一種能夠遍歷一種集合中的全部元素的機制
  2. 在 lua 中一般將迭代器表示爲函數
  3. 每調用一次函數,即返回集合中的「下一個」元素
  4. 每一個迭代器都須要在每次成功調用之間保存一些狀態
  5. 這樣就知道它如今所在的位置以及如何步進到一下位置
  6. 一個 closure 就是一種能夠訪問其外部嵌套環境中的局部變量的函數
  7. 這些變量可用於在成功調用之間保持狀態值
  8. 從而使 closure 能夠記住它在一次遍歷中所在的位置
  9. 建立一個 closure 必須建立它的「非局部變量」
  10. 一個closure 結構一般包含兩個函數函數

    1. closure 自己
    2. 建立該 closure 的工廠函數

while

  1. values 就是工廠,每次調用這個工廠,就會建立一個新的 closure 即迭代器其自己
  2. 這個 closure 將它的想要保存在其外部變量 ti
  3. 每當調用這個迭代器時,它就從列表 t 中返回下一個值
  4. 直到最後一個元素返回後,迭代器會返回 nil,表示迭代的結束
function values(t)
    local i = 0
    return function () 
        i = i + 1
        return t[i]
    end
end
t = {123, 333, 444}
iter = values(t) -- 建立迭代器
while true do
    local element = iter() -- 調用迭代器
    if element == nil then
        break
       end
    print(element)
end

泛型 for

  1. 泛型 for 記錄了每一次迭代循環
  2. 它在內部保存了迭代器函數,所以不須要 iter 變量
  3. 它在每次新迭代時調用迭代器,並在迭代器返回 nil 時循環結束
function values(t)
    local i = 0
    return function () 
        i = i + 1
        return t[i]
    end
end
t = {123, 333, 444}
-- 泛型 for
t = {123, 333, 444}
for element in values(t) do
    print(element)
end

高級用法

  1. 遍歷當前輸入文件中全部單詞的迭代器
  2. 須要保持的值lua

    1. 當前行的內容
    2. 以及該行所處的位置
  3. 使用 string.find 在當前行中調用,以當前位置做爲起始位置來搜索一個單詞
  4. 使用模式 %w+ 用來表示一個「單詞」, 英語匹配一個或多個文字或數字字符
  5. 若是找到了一個單詞,迭代器將當前位置更新爲該單詞以後的第一個字符,並返回該單詞
  6. 不然,迭代器讀取新的一行並重復這個搜索過程
  7. 若沒有剩餘的行,則返回 nil, 以此表示迭代的結束。
-- 編寫迭代器
function allwords()
    local line = io.read() -- 當前行
    local pos = 1 -- 一行中的位置
    return function () -- 迭代器函數
       while line do --  只要 line 不爲 nil 循環執行
            -- 返回開始位置和結束位置 
            local start, end = string.find(line, "%w+", pos)
            if s then -- 是否找到一個單詞
                pos = e + 1 -- 找到一個單詞,則移到這個單詞的下一個位置
                return string.sub(line, s) -- 返回該單詞
            else
                line = io.read() -- 這一行沒找到,嘗試讀取下一行
                pos = 1
            end
       end
       return nil -- 沒有剩餘行了,遍歷結束
    end
end

-- 調用迭代器
for word in allwords() do
    print(word)
end

泛型 for 的語義

  1. 上述的迭代器須要爲每個新的循環建立一個新的 closure,開銷很大
  2. 泛型 for 在循環過程內保存了迭代器函數
  3. 保存了 3 個值code

    1. 一個迭代器函數
    2. 一個恆定狀態
    3. 一個控制變量
-- var-list 變量列表 , exp-list 表達式列表, 多個元素可用 , 逗號分割
-- 一般表達式列表只有一個元素,即只有一句對迭代器工廠的調用
for <var-list> in <exp-list> do
    <code block>
end

for k, v in pairs(t) do
    print(k, v)
end

for line in io.lines() do
    io.write(line, "\n")
end
  1. 變量列表的第一元素稱爲「控制變量」,在循環過程當中該值毫不會爲 nil,當它爲 nil循環結束
  2. for 首先會先對 in 後面的表達式求值,這些表達式應返回 3 個值for 保存element

    1. 迭代器函數
    2. 恆定狀態
    3. 控制變量的初值
  3. 相似多重賦值,即只有最後一個表達式纔會產生多個結果
  4. 只會保留前 3 個值,多餘的值被丟棄,不足的話,用 nil 補足
  5. 初始化步驟後for 會以恆定狀態和控制變量來調用迭代器函數
  6. 而後 for迭代器函數的返回值賦予變量列表中的變量
  7. 若是變量列表中的第一個元素(即控制變量)的返回值爲 nil,則循環終止
  8. 不然,for 執行循環體,而後再次調用迭代器函數,並重復這個過程
  9. for 構建的角度來講,恆定狀態的內容與 for 自己是徹底無關的。for 只是保存了初始化中返回的值,並在調用迭代器函數時傳入該值。
for var_1, ..., var_n in <exp-list> do
    <code clock>
end

-- 上述代碼等價於以下代碼s
do
   -- _f 爲迭代器函數,_s 爲恆定狀態,控制變量的初值爲 a0
   local _f, _s, _var = <exp-list>
   while true do
        local var_1, ... var_n = _f(_s, _var)
        _var = var_1
        if _var == nil then
            break
        end
    end
    <code block>
end
  1. _f 爲迭代器函數,_s 爲恆定狀態,控制變量的初值爲 a₀
  2. 在循環過程當中控制變量的值依次爲 a₁ = f(s, a₀)a₂ = f(s, a₁) 以此類推
  3. 直至 ainil 結束循環
  4. 若是 for 還有其餘變量,那麼 他們也會在每次調用 f 後得到額外的值
相關文章
相關標籤/搜索