第一版是針對 Lua 5.0 編寫的。雖然對後續版本來說仍然有很大的關聯性,但還是有一些差異。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買本書,您也可以協助 支持 Lua 專案


7.4 – 具有複雜狀態的反覆運算器

反覆運算器通常需要保留比單一不變狀態和控制變數更多的狀態。最簡單的解決方案是使用封閉函數。另一種解決方案是將所有需要打包到表格中,並將此表格用作反覆運算的不變狀態。使用表格,反覆運算器可以在迴圈中保留所需的所有資料。此外,它可以在進行時變更資料。儘管狀態始終是相同的表格(因此是不變的),但表格內容會隨著迴圈而改變。由於此類反覆運算器在狀態中擁有所有資料,因此它們通常會捨棄一般 for 提供的第二個引數(反覆運算器變數)。

作為此技術的範例,我們將改寫反覆運算器 allwords,它會遍歷目前輸入檔案中的所有字詞。這次,我們將使用具有兩個欄位(linepos)的表格來保留其狀態。

啟動反覆運算的函數很簡單。它必須傳回反覆運算器函數和初始狀態

    local iterator   -- to be defined later
    
    function allwords ()
      local state = {line = io.read(), pos = 1}
      return iterator, state
    end
iterator 函數執行實際的工作
    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


只要有可能,您都應該嘗試撰寫無狀態迭代器,這些迭代器會將其所有狀態保存在 for 變數中。使用這些迭代器時,您在開始迴圈時不會建立新的物件。如果您無法將您的迭代放入該模型中,那麼您應該嘗試使用閉包。除了比較優雅之外,閉包通常比使用表格的迭代器更有效率:首先,建立閉包比建立表格更便宜;其次,存取上層值比存取表格欄位更快。稍後我們將看到另一種撰寫迭代器的方法,使用 coroutine。這是功能最強大的解決方案,但稍微貴一點。