新的 For 循环 |
|
for
' 语句语法。此页面有些历史意义(并且不再是新的)。参考手册[1] 对此进行了更完整的描述。
我(PhilippeLhoste)在 Lua 5.0 中使用新的 'for' 语法玩了一点(work0 以防语法/行为发生变化)。
我从 Roberto 在 2002/06/06 的邮件开始,邮件中给出了伪代码。由于我更喜欢长的变量名,所以我对其进行了重写,以便更好地(对我而言!)理解。让我在这里引用它,作为提醒
伪代码
for var1, ..., varn in expList do block end
do local _func, _state, var = <explist> while 1 do local var1, ..., varn = _func(_state, var1) var = var1 if var == nil then break end <block> end end
explist
是两个或三个表达式:一个函数 (_func
)、一个状态(用于数据的持久性)和一个初始值。它可以是一个返回这些值的函数。
_func
由 explist
返回,必须返回 n
个值,第一个值为 nil
时表示进程已耗尽。
我尝试了以下代码(也是 Roberto 提供的)
t = { "a", "b", "c" } for i, k in nexti(t) do print(i, k) end for k, v in next, t do print(k, v) end for k, v in t do print(k, v) end
结果相同。
在第一行中,'nexti
' 返回函数迭代器和作为参数给出的表。
在第二行中,'next
' 是函数 (_func
),而 't
' 是状态 (_state
)。
第三行是上述行的语法糖,以确保向后兼容性。
Roberto 给出的用于读取文件行的代码片段帮助我理解了上面的伪代码(我有点慢...)。
它是
function lines(filename) local f = assert(io.open(filename, "r")) return function () return f:read() or (assert(f:close()) and nil) end end for line in lines(file) do print(line) -- Or process line, etc. end
对于那些想知道匿名函数返回值的人
f:read()
读取一行,则 'or' 之后的代码不会被执行。
f:read()
为 nil
,我们返回第二部分
and nil
" 都强制此部分为 nil,因此循环结束。
我开始像这样重写它
function lines(filename) local f = assert(io.open(filename, "r")) local i = 0 return function () i = i + 1 return f:read() or (assert(f:close()) and nil), i end end local line, number for line, number in lines(file) do print("(" .. number .. ") " .. line) end
我们已经有了状态持久性... 我想这就是 5.0 闭包的魔力,匿名函数中的 'i
' 指向 lines() 中的局部变量。
我制作了一个最终版本,使用状态和初始值,如伪代码所示
function lines(filename) local f = assert(io.open(filename, "r")) local state = {} state.persistentValue = " " state.counter = 0 return function (_state, _previousValue) _state.persistentValue = "." .. _state.persistentValue _state.counter = _state.counter + 1 print(_state.persistentValue .. _previousValue) return f:read() or (assert(f:close()) and nil), _state.counter end, state, "First value" end
但我不再确定这种状态相对于先前版本的优势... 好吧,它看起来更像 OO,我可能遗漏了一些副作用。
RobertoIerusalimschy 回答道:这取决于个人喜好。使用状态的优势在于,在运行 for 循环时,不需要创建任何新的“对象”(表、闭包等)。`nexti
` 就是一个例子。在“更重”的循环中,额外对象的成本可以忽略不计。例如,在文件示例中,您已经需要打开文件、创建文件句柄、创建多个字符串(行)等等。一个额外的闭包(或表)对总成本的影响微乎其微。