我对无状态迭代器的概念感到困惑。作为练习,我编写了一个迭代器来打印给定字符串的所有非空子串。代码如下。
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
本地函数中更改此表中的字段。这个迭代器是无状态还是复杂状态?如果它不是无状态的,有没有办法用无状态迭代器实现这个功能?
谢谢。
答案 0 :(得分:2)
这不是stateless iterator,而且确实是complex state的迭代器。
在无状态迭代器中,只有一个控制变量,并且它应该在整个迭代器中被视为纯值。
您可以考虑使用闭包来实现此功能。不是无状态的,但确实使用upvalues而不是表查找,这应该更有效。
local function allSubstrings (str)
if type(str) ~= "string" or str == "" then
return function () end -- NOP out on first iteration
end
local length = #str
local start, ending = 1, 1
return function ()
if ending > length then return nil end
local st, ed = start, ending
if start == ending then
ending = ending + 1
start = 1
else
start = start + 1
end
return string.sub(str, st, ed)
end
end
for substr in allSubstrings("abcd123") do
print(substr)
end
答案 1 :(得分:2)
PIL-chapter about stateless iterators州:
顾名思义,无状态迭代器是一个迭代器,它不会保留任何状态。因此,我们可以在多个循环中使用相同的无状态迭代器,从而避免创建新闭包的成本。
代码表示两个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
的所有upvalues必须是不可变的),并提供一种复制/克隆此状态以供以后迭代的方法:
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
这仍然是不是无状态迭代器,但它比具有堆分配的循环控制变量的无状态迭代器更具内存效率,并且它允许您重新启动迭代。
答案 2 :(得分:0)
PIL书中称“复杂状态的迭代器” http://www.lua.org/pil/7.4.html