首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Lua 迭代器與泛型 for 循環深度解析:從閉包到無狀態迭代器

     編輯:Java 相關知識

迭代器是遍歷集合的核心抽象,Lua 通過閉包實現有狀態迭代器,通過泛型 for 的三值協議(迭代器函數、恆定狀態、控制變量)統一遍歷語義。本文從基礎模式進階到 ipairs/pairs 內部實現,揭示無狀態迭代器的高效原理。

一、最簡單的迭代器:閉包捕獲狀態

function values(t)
    local i = 0
    return function()  -- 閉包捕獲 i 和 t
        i = i + 1
        return t[i]
    end
end

local testTb = {10, 20, 30}
for v in values(testTb) do
    print(v)  -- 10, 20, 30
end

每次調用返回的匿名函數保持對 i 的引用,形成「函數+狀態」的迭代器模式。

二、泛型 for 的三值協議

語法:for <var-list> in <exp-list> do <body> end

執行流程:

  1. 求值 <exp-list>,必須返回三個值:迭代器函數、恆定狀態、控制變量初值。
  2. 循環體執行前,以 (恆定狀態, 控制變量) 調用迭代器函數。
  3. 將返回值賦值給 <var-list>。
  4. 若第一個返回值為 nil,循環終止;否則執行循環體,更新控制變量為第一個返回值,回到第 2 步。

等價 while 代碼:

do
    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
        <body>
    end
end

三、無狀態迭代器:ipairs 實現原理

無狀態迭代器不保存自身狀態,完全依賴 恆定狀態(被遍歷表)和 控制變量(當前索引)計算下一元素。優勢:可在多個循環復用同一迭代器函數,避免創建閉包開銷。

ipairs 實現:

local function iter(a, i)  -- a: 恆定狀態(表), i: 控制變量(索引)
    i = i + 1
    local v = a[i]
    if v then return i, v end  -- 返回新控制變量 和 元素值
end

function ipairs(a)
    return iter, a, 0  -- 迭代器函數、恆定狀態、控制變量初值 0
end

使用示例:

local aTb = {"One", "Two", "Three"}
for i, v in ipairs(aTb) do
    print(i, v)  -- 1 One, 2 Two, 3 Three
end

pairs 實現(基於 next 基礎函數):

function pairs(t)
    return next, t, nil  -- next 函數、表、初始控制變量 nil
end

next(t, k) 返回表中「下一個」鍵值對(無序)。next(t, nil) 返回第一對。可用 next(t, nil) == nil 判斷表是否為空。

四、ipairs vs pairs 核心差異

特性ipairspairs
適用表類型數組部分(整數鍵 1..n 連續)任意表(含哈希部分)
遍歷順序嚴格 1,2,3...n無序(實現相關)
遇到 nil 值直接終止遍歷繼續遍歷其他鍵
返回鍵類型整數索引任意類型鍵
控制變量初值0nil

記憶口訣:ipairs = integer pairs(只遍歷整數鍵數組部分,有序、遇 nil 止)。

五、有狀態迭代器:表封裝狀態

當需要在遍歷過程中修改被遍歷表、或維護複雜遍歷上下文時,可用表保存狀態:

function makeStatefulIter(t)
    local state = { data = t, idx = 0, filtered = {} }
    return function()
        -- 可在此修改 state.filtered、state.idx 等
        state.idx = state.idx + 1
        return state.data[state.idx]
    end, state, 0  -- 將狀態表作為恆定狀態傳遞
end

此模式下,迭代器函數通過 恆定狀態 參數訪問並修改共享狀態表。

六、實戰:自定義過濾迭代器

function filter(t, predicate)
    local i = 0
    return function()
        i = i + 1
        while t[i] ~= nil do
            if predicate(t[i]) then return i, t[i] end
            i = i + 1
        end
        return nil
    end
end

-- 使用:只遍歷偶數
for i, v in filter({1,2,3,4,5,6}, function(x) return x%2==0 end) do
    print(i, v)  -- 2 2, 4 4, 6 6
end

七、性能與最佳實踐

  1. 優先使用 ipairs/pairs:C 實現,無 Lua 閉包開銷,JIT 優化最好。
  2. 數組遍歷用數值 for:for i=1, #t do ... end 最快,避免迭代器函數調用開銷。
  3. 避免在迭代器中創建表/閉包:熱路徑傳遞預分配表復用。
  4. 泛型 for 變量聲明在循環內:for k,v in pairs(t) do local ... end,作用域最小化。

理解泛型 for 的三值協議,是掌握 Lua 遍歷抽象的鑰匙。無狀態迭代器以「函數不變、狀態外置」的函數式思想,實現了高效與通用的完美平衡,這正是 Lua 設計哲學「機制而非策略」的生動體現。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved