不借助表存储变长参数,实现迭代器返回最后值的可行性探究
迭代器最后返回值的实现与优化
要实现一个接收泛型for循环迭代器(包含迭代器函数、不变状态和循环控制变量),返回最后一次迭代中控制变量值的函数非常简单:
function iterator_last_value(iterator, state, control_var) local last for value in iterator, state, control_var do last = value end return last end print(iterator_last_value(("hello world"):gmatch"%a+")) -- world
这个函数可以轻松扩展,支持Lua局部寄存器限制内的任意固定数量参数。如果要支持返回变长参数的迭代器,我们可以把最后一组变长参数存储在表里,但这种写法需要放弃Lua的for循环语法糖:
function iterator_last(iterator, state, control_var) local last = {} local last_n = 0 local function iter(...) local control_var = ... if control_var == nil then return table.unpack(last, 1, last_n) end last = {...} last_n = select("#", ...) return iter(iterator(state, control_var)) end return iter(iterator(state, control_var)) end print(iterator_last(ipairs{"a", "b", "c"})) -- 3, c
这个实现能正常运行,但每次迭代都会创建一个临时表,产生垃圾对象。如果把这段代码:
last = {...} last_n = select("#", ...)
替换成:
last_n = select("#", ...) for i = 1, last_n do last[i] = select(i, ...) end
就能复用同一个表——虽然用select手动填充表的效率比{...}低,但能大幅减少临时表的创建(每次调用iterator_last只会生成一个临时表)。
我们能否实现一个支持变长返回值的iterator_last函数,无需借助表、协程等方式存储变长参数以避免显著开销,仅通过函数调用传递栈上的变长参数? 我推测这无法实现,但尚未能证明或证伪。
内容的提问来源于stack exchange,提问作者Luatic
相关产品推荐
相关产品推荐

