在过去的几个月里,我一直在与Lua打交道,我非常喜欢大部分功能,但我仍然遗漏了其中的一些内容:
continue
?答案 0 :(得分:63)
语言管理词汇范围的方式会产生包含goto
和continue
的问题。例如,
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
的外部变量,并且该局部的范围扩展到until
语句的条件,因此条件正在测试最里面的a
。
如果存在continue
,则必须在语义上将其限制为仅在条件中使用的所有变量进入范围之后才有效。这是向用户记录并在编译器中强制执行的困难条件。已经讨论了围绕这个问题的各种提案,包括使用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
很明显,除非你有一系列精心设计的剔除来控制循环操作,否则通常不会有负担。
答案 1 :(得分:62)
在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支持此功能
答案 2 :(得分:37)
您可以将循环体包装在其他repeat 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
答案 3 :(得分:16)
至于解决方法,你可以在一个函数和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
或者,如果您同时需要break
和continue
功能,请让本地函数执行测试,例如
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
答案 4 :(得分:15)
Straight from the designer of Lua himself:
我们对“继续”的主要关注是,有一些其他控制结构(在我们看来)或多或少与“继续”一样重要,甚至可能取而代之。 (例如,打破标签[在Java中]或甚至更通用的goto。)“continue”似乎并不比其他控制结构机制更特殊,除了它存在于更多语言中。 (Perl实际上有两个“continue”语句,“next”和“redo”。两者都很有用。)
答案 5 :(得分:8)
我之前从未使用过Lua,但我用Google搜索并想出了这个:
这是一个常见的抱怨。 Lua的作者认为,继续只是众多可能的新控制流机制中的一种(事实上它不能与重复范围规则一起使用/直到次要因素。)
在Lua 5.2中,有一个goto语句,可以很容易地用来做同样的工作。
答案 6 :(得分:6)
Lua是一种轻量级的脚本语言,希望尽可能缩小。例如,许多一元运算(例如前后递增)不可用
您可以使用goto like代替
arr = {1,2,3,45,6,7,8}
for key,val in ipairs(arr) do
if val > 6 then
goto skip_to_next
end
# perform some calculation
::skip_to_next::
end
答案 7 :(得分:5)
我们可以实现如下,它会跳过偶数
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
答案 8 :(得分:4)
我们多次遇到过这种情况,我们只是使用一个标志来模拟继续。我们也试图避免使用goto语句。
示例:代码打算从i = 1到i = 10打印语句,除了i = 3。此外,它还打印&#34;循环开始&#34;循环结束&#34;,&#34;如果开始&#34;,&#34;如果结束&#34;模拟代码中存在的其他嵌套语句。
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
是通过将所有剩余的语句包含在带有测试标志的循环结束范围之前实现的。
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
我并不是说这是最好的方法,但它对我们来说非常有效。
答案 9 :(得分:3)
再次使用反转,您只需使用以下代码:
for k,v in pairs(t) do
if not isstring(k) then
-- do something to t[k] when k is not a string
end
答案 10 :(得分:-1)
因为这是不必要的。开发人员很少需要它。
A)当您有一个非常简单的循环(例如1或2线)时,您只需扭转循环条件,它仍然可读性很强。
B)在编写简单的过程代码(也就是上个世纪我们编写代码的方式)时,还应该应用结构化编程(又就是上个世纪我们编写更好的代码的方式)
C)如果您正在编写面向对象的代码,则循环主体应包含不超过一或两个方法调用,除非它可以用一或两行表示(在这种情况下,请参阅A)
D)如果您正在编写功能代码,只需为下一次迭代返回一个简单的尾调用即可。
唯一要使用continue
关键字的情况是,如果要像Lua一样编写Lua的代码,
除非A)适用,在这种情况下,不需要任何变通办法,您应该进行结构化,面向对象或函数式编程。这些就是Lua构建的范式,因此,如果您竭尽所能避免使用它们的模式,那么您将与该语言作斗争。