lua - 下面的Lua迭代器是无状态的吗?

标签 lua iterator

我对无状态迭代器的概念感到困惑。作为练习,我编写了一个迭代器来打印给定字符串的所有非空子字符串。代码如下。

local function iter(state, i)
    local str = state.str
    if type(str) ~= "string" or str == "" then return nil end
    if state.ending > #str then return nil end

    local start = state.start
    local ending = state.ending

    if start == ending then
        state.ending = ending + 1
        state.start = 1
    else
        state.start = start + 1
    end

    return string.sub(str, start, ending)
end

function allSubstrings(str)
    return iter, { str = str, start = 1, ending = 1 }, nil
end

for substr in allSubstrings("abcd123") do
    print(substr)
end

我使用一个表{ str = str, start = 1,ending = 1 }作为所谓的不变状态,但是我必须在中更改这个表中的字段iter 本地函数。那么这个迭代器是无状态的还是具有复杂状态的?如果它不是无状态的,有没有办法用无状态迭代器实现这个功能?

谢谢。

最佳答案

PIL-chapter about stateless iterators状态:

As the name implies, a stateless iterator is an iterator that does not keep any state by itself. Therefore, we may use the same stateless iterator in multiple loops, avoiding the cost of creating new closures.

在代码中,这意味着两个 for 循环:

f, s, var = pairs( t )
for k,v in f, s, var do print( k, v ) end
for k,v in f, s, var do print( k, v ) end

应该产生相同的输出。仅当不变状态 s 和迭代器函数 f 的任何上值在迭代过程中都没有改变时才有效,否则第二个 for 循环将具有与第一个循环不同的起始条件。

所以,不,您的迭代器不是无状态迭代器,因为您在迭代期间更改了不变状态。

有一种方法可以让你的迭代器无状态(流行的 Lua 库 luafun 广泛使用这种技术):将所有可变状态保留在循环控制变量 var 中(即使你需要在每个分配步骤中分配一个新表):

local function iter( str, var )
  if type( str ) ~= "string" or str == "" then return nil end
  if var[ 2 ] > #str then return nil end
  local start, ending = var[ 1 ], var[ 2 ]
  if start == ending then
    return { 1, ending+1 }, string.sub( str, start, ending )
  else
    return { start+1, ending }, string.sub( str, start, ending )
  end
end

function allSubstrings2( str )
  return iter, str, { 1, 1 }
end

for _,substr in allSubstrings2( "abcd123" ) do
  print( substr )
end

缺点是第一个迭代变量 var (循环控制变量)对于迭代器的用户来说没有任何有用的意义,并且由于您必须为每个迭代步骤分配一个表,因此“避免为另一个循环创建新闭包的成本并不重要。

luafun 无论如何都会这样做,因为它没有能力重新创建迭代器元组(它是通过外部代码的函数参数传递的),并且对于某些算法,您绝对需要运行相同的算法迭代多次。

此方法的替代方法是将所有可变状态集中在“不变状态”s 中(f 的所有上值必须是不可变的),并提供一种方法复制/克隆此状态以供以后迭代使用:

f, s, var = allSubstrings("abcd123")
s2 = clonestate( s )
for str in f, s, var do print( str ) end
for str in f, s2, var do print( str ) end

这仍然不是无状态迭代器,但它比具有堆分配循环控制变量的无状态迭代器更节省内存,并且它允许您重新启动迭代。

关于lua - 下面的Lua迭代器是无状态的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38737036/

相关文章:

lua - xCode Simulator 中的 Corona 应用程序的紫色背景

python - 如何使用 scrapy_splash 包在表单发布后重定向?

c++ - 在 C++ 中嵌入 Lua : Accessing C++ created through Lua, 回到 C++(或将结果从 Lua 返回到 C++)

lua - 在 Lua 中创建要执行的任务列表

c++ - vector 结束迭代器

python - 是否有一种 pythonic 方法来迭代范围字典以构建新字典?

c++11 - 何时使用 ostream_iterator

lua - 使用 Lua 检测键盘按键组合

java - 无法遍历哈希集

loops - 如何在 Lua 中的二维表上创建迭代器?