gpt4 book ai didi

lua - Lua 中有状态迭代器和无状态迭代器的区别

转载 作者:行者123 更新时间:2023-12-04 13:50:31 25 4
gpt4 key购买 nike

Lua中的无状态迭代器和有状态迭代器有什么区别,请详细解释一下?我们什么时候需要使用无状态,什么时候需要另一个?我需要例子来理解这个概念。

最佳答案

首先让我们同意一个定义:(在 Lua 中)迭代器是一个类似函数的对象,每次调用它时都会返回序列中的下一个值。我认为重写 for 会有所帮助完成的迭代是Lua ref手册:

for itemlist in expression do block end

逻辑上等价于(伪代码):
do
local func, seq, controlVar = expression
while true do
local itemlist = func(seq, controlVar)
if first of itemlist == nil then break end
controlVar = first of itemlist

block (which uses items in itemlist)
end
end

在哪里 expression是数据的三元组(或返回此类三元组的函数调用):
  • func是实际的迭代器函数
  • seq是在
  • 上迭代的序列吗?
  • controlVar是循环控制变量

  • 迭代状态是在被迭代的序列中查找下一个项目可能需要的任何状态。因此,无状态迭代器是 func不包含任何此类状态:您可以调用 func(seq, controlVar)在任何时候,返回值总是相同的(如果 seq 没有​​改变);它不取决于通话前发生的事情。

    如上所示,Lua 支持一个循环控制变量。因此,为了使序列可以通过无状态迭代器进行迭代,必须能够根据一个循环控制变量确定序列中的下一项。即,必须可以单独从“(s,controlVar)”中找出“下一个项目”。 ipairs()生成执行此操作的迭代器: ipairs(s)返回三元组 (iterFunction, s, 0) ; iterFunction可以给 s和索引 0,并返回 1, s[1] ,然后 2, s[2]等(对于 N 个项目的表格最终什么都没有)。

    如果查找序列中的下一项需要多个循环控制变量怎么办?还是取决于其他变量的状态,应该在迭代过程中保存?例子:
  • 无限迭代器可能需要跟踪“第一个”项目,以便一旦到达序列末尾,它可以从第一个项目恢复;
  • 图迭代器可能需要在深度优先搜索中跟踪“最近的兄弟”,以便一旦到达分支的末尾,它就可以继续下一个最近的兄弟。

  • 有状态迭代器保存有关迭代的状态,以便可以找到下一个项目。在 Lua 中,如果迭代器函数是闭包(具有上值的函数)或仿函数(表现为函数的表,即具有 __call 元方法),则这是可能的。 up 值(闭包)或数据成员(仿函数)可以存储所需的状态。

    无状态迭代器总是可以包装成有状态迭代器。对于 ipairs :
    function statefulIpairs(s)
    local f, s, var = ipairs(s)
    return function()
    local i, v = f(s,var)
    var = i
    return i, v
    end
    end

    这可以称为
    tbl = {'a', 'b', 'c', 'd'}
    sip = statefulIpairs(tbl) -- sip is stateful iter specific to tbl
    for i,v in sip() do print(i,v) end

    有状态迭代器的开发人员决定迭代器具有哪些功能:迭代器的 API 可能允许倒带、反转方向或其他操作。这甚至在闭包的情况下也是可能的:可以使用附加参数来访问附加功能。例如,接受第三个参数,当它非 nil 时,重置为序列的开头:
    function resetableStatefulIpairs(s)
    local f, s, var = ipairs(s)
    local start = var
    return function(a,b,reset)
    if reset ~= nil then var = start; return end
    local i, v = f(s,var)
    var = i
    return i, v
    end
    end

    sip = resetableStatefulIpairs(tbl) -- sip is stateful iter specific to tbl
    for i,v in sip() do print(i,v) end
    sip(nil, nil, true) -- reset it
    for i,v in sip() do print(i,v) end

    更新一个更简洁的例子是如何生成一个函数迭代器,它接受命令,这样您就可以“......在序列中的任何位置停止并迭代序列的其余部分 3 次”(根据@deduplicator 的要求):
    function iterGen(seq, start)
    local cvar = start or 1
    return function(cmd)
    if cmd == nil then
    if cvar > #seq then return nil, nil end
    val = seq[cvar]
    cvar = cvar + 1
    return cvar-1, val

    else
    cmd = cmd[1]
    if cmd == 'rewind' then
    cvar = start or 1

    elseif cmd == 'newstart' then
    start = cvar
    end
    end
    end
    end

    有了以上内容:
    > s = {1,2,3,4,5,6,7}
    > iter = iterGen(s)
    > for i,v in iter do print(i,v); if i==3 then break end end
    1 1
    2 2
    3 3
    > iter {'newstart'} -- save current as the new start pos
    > for i,v in iter do print(i,v) end -- continue till end
    4 4
    5 5
    6 6
    7 7
    > iter {'rewind'}
    > for i,v in iter do print(i,v) end
    4 4
    5 5
    6 6
    7 7
    > iter {'rewind'}
    > for i,v in iter do print(i,v) end
    4 4
    5 5
    6 6
    7 7

    正如所展示的,有状态迭代器没有什么特别之处,除了迭代的状态在迭代器内部这一事实外,如上所述,开发人员可以公开所需的功能,如上面的 rewind 和 newstart。使用无状态迭代器,没有限制。

    将迭代器设计为仿函数将是一个更自然的 API,因为从那时起迭代器“函数”具有可以调用的“方法”,但创建可命令函数是一个有趣的挑战。

    关于lua - Lua 中有状态迭代器和无状态迭代器的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22724092/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com