以下 Lua 迭代器是否无状态?
我对无状态迭代器的概念感到困惑。为了练习,我编写了一个迭代器,用于打印给定字符串的所有非空子字符串。代码如下。
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 本地函数中更改该表中的字段。那么这个迭代器是无状态的还是具有复杂的状态?如果它不是无状态的,有没有一种使用无状态迭代器实现此功能的方法?
谢谢。
这不是一个stateless iterator,而是一个有complex state的迭代器。
在stateless iterators中,只有一个控制变量,它应该在整个迭代器中被视为一个纯值。
您可以考虑使用闭包来实现这个。虽然不是完全无状态,但使用了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
正如其名称所示,无状态迭代器是一种不保留任何状态的迭代器。因此,我们可以在多个循环中使用同一个无状态迭代器,避免创建新闭包的成本。
在代码中,这意味着以下两个 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 虚拟机加密load(string.dump(function)) 后执行失败问题如何解决
- 我想创建一个 Nginx 规则,禁止访问
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?

PIL 书中将其称为“具有复杂状态的迭代器”。
http://www.lua.org/pil/7.4.html