为什么Lua没有“继续”的说法?

我在过去几个月里一直和Lua打交道,而且我非常喜欢大部分function,但是我仍然错过了其中的一些东西:

  • 为什么没有continue
  • 有什么解决方法呢?

语言pipe理词汇范围的方式造成了包括gotocontinue 。 例如,

 local a=0 repeat if f() then a=1 --change outer a end local a=f() -- inner a until a==0 -- test inner a 

循环体内的local a声明掩盖了名为a的外部variables,并且该局部范围扩展到了until语句的条件,所以条件是testing最内部的a

如果continue存在,则只有在条件中使用的所有variables已经进入范围之后,才能在语义上受到限制。 这是向用户提供文档并在编译器中执行的一个困难条件。 围绕这个问题的各种build议已经被讨论过,包括简单的答复,不要continue repeat ... until循环的风格。 到目前为止,还没有一个足够引人注目的用例将它们包含在语言中。

解决方法通常是反转会导致continue执行的条件,并在该条件下收集循环体的其余部分。 所以,下面的循环

 -- not valid Lua 5.1 (or 5.2) for k,v in pairs(t) do if isstring(k) then continue end -- do something to t[k] when k is not a string end 

可以写

 -- valid Lua 5.1 (or 5.2) for k,v in pairs(t) do if not isstring(k) then -- do something to t[k] when k is not a string end end 

这是很清楚的,通常不是一个负担,除非你有一系列控制循环操作的精心挑选。

在Lua 5.2中最好的解决方法是使用goto:

 -- prints odd numbers in [|1,10|] for i=1,10 do if i % 2 == 0 then goto continue end print(i) ::continue:: end 

自2.0.1版本以来,这在LuaJIT中得到了支持

你可以在循环体中joinrepeat until true ,然后使用do break end来继续。 当然,如果你还打算真正break循环,你需要设置额外的标志。

这将循环5次,每次打印1,2和3。

 for idx = 1, 5 do repeat print(1) print(2) print(3) do break end -- goes to next iteration of for print(4) print(5) until true end 

这个结构甚至可以转换成Lua字节码中的一个操作码JMP

 $ luac -l continue.lua main <continue.lua:0,0> (22 instructions, 88 bytes at 0x23c9530) 0+ params, 6 slots, 0 upvalues, 4 locals, 6 constants, 0 functions 1 [1] LOADK 0 -1 ; 1 2 [1] LOADK 1 -2 ; 3 3 [1] LOADK 2 -1 ; 1 4 [1] FORPREP 0 16 ; to 21 5 [3] GETGLOBAL 4 -3 ; print 6 [3] LOADK 5 -1 ; 1 7 [3] CALL 4 2 1 8 [4] GETGLOBAL 4 -3 ; print 9 [4] LOADK 5 -4 ; 2 10 [4] CALL 4 2 1 11 [5] GETGLOBAL 4 -3 ; print 12 [5] LOADK 5 -2 ; 3 13 [5] CALL 4 2 1 14 [6] JMP 6 ; to 21 -- Here it is! If you remove do break end from code, result will only differ by this single line. 15 [7] GETGLOBAL 4 -3 ; print 16 [7] LOADK 5 -5 ; 4 17 [7] CALL 4 2 1 18 [8] GETGLOBAL 4 -3 ; print 19 [8] LOADK 5 -6 ; 5 20 [8] CALL 4 2 1 21 [1] FORLOOP 0 -17 ; to 5 22 [10] RETURN 0 1 

第一部分在FAQ中被解释为被杀的人指出的。

至于解决方法,你可以将循环的主体包装在一个函数中,并且尽早return ,例如

 -- Print the odd numbers from 1 to 99 for a = 1, 99 do (function() if a % 2 == 0 then return end print(a) end)() end 

或者,如果你想同时breakcontinuefunction,让本地function执行testing,例如

 local a = 1 while (function() if a > 99 then return false; -- break end if a % 2 == 0 then return true; -- continue end print(a) return true; -- continue end)() do a = a + 1 end 

直接从Lua的devise师本人 :

我们主要关注“继续”的是,还有其他几个控制结构(在我们看来)与“继续”或多或less一样重要,甚至可能取而代之。 (例如,打破标签(如Java),甚至是更通用的转换。)除了以更多的语言存在之外,“继续”似乎不像其他控制结构机制那么特殊。 (Perl实际上有两个“继续”语句,“下一个”和“重做”,两者都是有用的。)

我以前从来没有用过Lua,但是我用Googlesearch了这个:

http://www.luafaq.org/

检查问题1.26 。

这是一个常见的投诉。 Lua的作者认为,继续只是许多可能的新的控制stream动机制之一(事实上它不能适用范围规则的重复/直到是次要因素)。

在Lua 5.2中,有一个很容易用来做同样工作的goto语句。

再次反转,你可以简单地使用下面的代码:

 for k,v in pairs(t) do if not isstring(k) then -- do something to t[k] when k is not a string end 

我们可以做到如下,它会跳过偶数

 local len = 5 for i = 1, len do repeat if i%2 == 0 then break end print(" i = "..i) break until true end 

O / P:

 i = 1 i = 3 i = 5 

我们多次遇到这种情况,我们只是使用一个标志来模拟继续。 我们尽量避免使用goto语句。

例如:代码打算打印1到10之间的数字,3除外。另外还打印“循环开始”,“循环结束”,“如果开始”和“如果结束”来模拟代码中存在的其他语句,嵌套语句。

 size = 10 for i=1, size do print("loop start") if whatever then print("if start") if (i == 3) then print("i is 3") --continue end print(j) print("if end") end print("loop end") end 

是通过用一个testing标志封闭所有剩余的语句直到循环的结束范围来实现的。

 size = 10 for i=1, size do print("loop start") local continue = false; -- initialize flag at the start of the loop if whatever then print("if start") if (i == 3) then print("i is 3") continue = true end if continue==false then -- test flag print(j) print("if end") end end if (continue==false) then -- test flag print("loop end") end end 

我并不是说这是最好的方法,但它对我们来说是完美的。