Lua迭代器与泛型for

在Lua中,迭代器是一种强大的编程模式,它允许我们以统一的方式遍历各种数据结构。迭代器的核心思想是将遍历逻辑封装起来,提供简洁的接口来访问集合中的元素。

迭代器的基本概念

什么是迭代器?

在Lua中,迭代器本质上是一个函数,每次调用这个函数会返回下一个元素。一个完整的迭代器包含两部分:

  1. 闭包(迭代器)本身:负责返回下一个元素
  2. 工厂函数:创建闭包及其内部变量的函数

基本实现示例

lua 复制代码
function values(t)
    local i = 0
    return function()
        i = i + 1
        if i <= #t then
            return t[i]
        else
            return nil 
        end
    end
end

在这个例子中:

  • values工厂函数
  • 返回的匿名函数是迭代器(闭包)
  • i状态变量,被闭包捕获

使用迭代器

手动调用方式
lua 复制代码
t = {1, 2, 3, 4, 5}
iter = values(t)
while true do
    local element = iter()
    if element == nil then break end
    print(element)
end
泛型for方式(推荐)
lua 复制代码
for element in values(t) do 
    print(element)
end

泛型for语法更加简洁,Lua内部会自动管理迭代器的生命周期。

泛型for的内部机制

语法结构

lua 复制代码
for var-list in exp-list do 
    body
end

详细语法

lua 复制代码
for var1, var2, ... in iterator_func, state, initial_value do
    -- 循环体
end

内部实现机制

泛型for在内部保存了三个值:

  1. 迭代函数(iterator function)
  2. 不可变状态(invariant state)
  3. 控制变量(control variable)

上述语法等价于:

lua 复制代码
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

无状态迭代器

概念

无状态迭代器(stateless iterator)是一种自身不保存任何状态的迭代器。所有的状态信息都通过参数传递,使得迭代器函数本身是纯函数。

基本实现

lua 复制代码
local function iter(t, i)
    i = i + 1
    local v = t[i]
    if v then
        return i, v
    end
end

function ipairs(t)
    return iter, t, 0
end

链表遍历示例

lua 复制代码
local function getnext(list, node)
    if not node then
        return list
    else
        return node.next
    end
end

function traverse(list)
    return getnext, list, nil
end

注意 :初始变量值是nil而不是list,这是链表遍历的关键。

按键排序遍历表

lua 复制代码
function pairsByKeys(t, f)
    local a = {}
    for n in pairs(t) do
        a[#a + 1] = n 
    end
    table.sort(a, f)
    local i = 0
    return function()
        i = i + 1
        return a[i], t[a[i]]
    end
end

for name, line in pairsByKeys(lines) do
    print(name, line)
end

有状态迭代器

概念

有状态迭代器通过闭包保存状态信息,每次调用时访问和修改内部状态。

基本结构

lua 复制代码
for var1, var2, ... in iterator_func() do
    -- 循环体
end

内部机制

lua 复制代码
function iterator_func()
    local state = initial_state  -- 状态变量
    return function()
        -- 访问和修改状态
        -- 返回下一个值或nil
    end
end

实现示例

lua 复制代码
function stateful_squares(max)
    local count = 0  -- 状态变量
    return function()
        count = count + 1
        if count <= max then
            return count, count * count
        else
            return nil
        end
    end
end

for i, square in stateful_squares(3) do
    print(i .. " 的平方是 " .. square)
end

两种迭代器的对比

无状态迭代器

优势:

  • 线程安全:无状态,可并发使用
  • 内存效率:不保存状态,内存占用少
  • 可重入:可以同时使用多个实例
  • 函数式:纯函数,易于测试

适用场景:

  • 数学计算:斐波那契数列、素数生成
  • 数据转换:数组映射、过滤
  • 多线程环境:并发处理
  • 内存敏感应用:嵌入式系统

有状态迭代器

优势:

  • 实现简单:状态管理直观
  • 性能优化:状态访问快速
  • 灵活性:可以保存复杂状态

劣势:

  • 不可重入:不能同时使用多个实例
  • 线程不安全:状态共享问题
  • 内存开销:需要保存状态

适用场景:

  • 文件处理:逐行读取文件
  • 网络流:处理数据流
  • 复杂状态:游戏状态机
  • 一次性遍历:数据处理管道

实际应用示例

文件行迭代器

lua 复制代码
function lines(filename)
    local file = io.open(filename, "r")
    if not file then return nil end
    
    return function()
        local line = file:read()
        if not line then
            file:close()
            return nil
        end
        return line
    end
end

-- 使用
for line in lines("data.txt") do
    print(line)
end

范围迭代器

lua 复制代码
function range(start, stop, step)
    step = step or 1
    local current = start - step
    
    return function()
        current = current + step
        if step > 0 and current <= stop then
            return current
        elseif step < 0 and current >= stop then
            return current
        else
            return nil
        end
    end
end

-- 使用
for i in range(1, 10, 2) do
    print(i)  -- 输出: 1, 3, 5, 7, 9
end

应用

1. 选择合适的迭代器类型

  • 简单遍历:使用无状态迭代器
  • 复杂状态:使用有状态迭代器
  • 并发环境:优先选择无状态迭代器

2. 错误处理

lua 复制代码
function safe_iterator(data)
    local index = 0
    return function()
        index = index + 1
        if index <= #data then
            return data[index]
        else
            return nil
        end
    end
end

3. 性能优化

lua 复制代码
-- 避免在循环中创建新表
function efficient_pairs(t)
    local keys = {}
    for k in pairs(t) do
        keys[#keys + 1] = k
    end
    table.sort(keys)
    
    local i = 0
    return function()
        i = i + 1
        local k = keys[i]
        if k then
            return k, t[k]
        end
    end
end

总结

Lua的迭代器机制提供了强大而灵活的遍历能力:

  1. 泛型for简化了迭代器的使用
  2. 无状态迭代器适合并发和函数式编程
  3. 有状态迭代器适合复杂状态管理
  4. 选择合适的类型是性能优化的关键

相关推荐
l1t8 小时前
利用DeepSeek辅助修改luadbi-duckdb读取DuckDB decimal数据类型
c语言·数据库·单元测试·lua·duckdb
Mr. zhihao15 小时前
Java 反序列化中的 boolean vs Boolean 陷阱:一个真实的 Bug 修复案例
java·bug·lua
ellis197018 小时前
Lua代码混淆-Prometheus方案教程
unity·lua
烛阴1 天前
从create到yield:Lua协程完全上手指南
前端·lua
利来利往1 天前
lua table.remove引发的偶现bug
bug·lua·table.remove
初见无风2 天前
3.1 Lua代码中的元表与元方法
开发语言·lua·lua5.4
千里镜宵烛2 天前
Lua--数据文件和持久性
开发语言·junit·lua
壹佰大多2 天前
【Redisson分布式锁源码分析-3】
数据结构·分布式·mysql·spring·spring cloud·wpf·lua
l1t3 天前
对luasql-duckdb PR的测试
c语言·数据库·单元测试·lua·duckdb
初见无风3 天前
3.3 Lua代码中的协程
开发语言·lua·lua5.4