Loops 为什么Lua没有;“继续”;陈述
在过去的几个月里,我一直在与Lua打交道,我真的很喜欢其中的大部分功能,但我仍然缺少一些功能:Loops 为什么Lua没有;“继续”;陈述,loops,lua,language-design,Loops,Lua,Language Design,在过去的几个月里,我一直在与Lua打交道,我真的很喜欢其中的大部分功能,但我仍然缺少一些功能: 为什么没有继续 有什么解决办法 我以前从未使用过Lua,但我在谷歌上搜索了一下,得出了以下结论: 检查 这是常见的抱怨。Lua的作者认为continue只是许多可能的新控制流机制中的一个(它不能与repeat/until的范围规则一起工作这一事实是次要因素) 在Lua5.2中,有一个goto语句,可以很容易地用于完成相同的工作 该语言管理词法范围的方式会产生问题,包括goto和continue。比
- 为什么没有
继续
- 有什么解决办法
该语言管理词法范围的方式会产生问题,包括
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
的外部变量,该局部变量的范围扩展到语句的整个条件,直到
语句,因此该条件正在测试最里面的a
如果存在continue
,则必须在语义上对其进行限制,使其仅在条件中使用的所有变量进入范围后才有效。这是一个很难向用户记录并在编译器中强制执行的条件。围绕这个问题的各种建议已经被讨论过,包括简单的答案是不允许继续和重复。。。直到循环的样式。到目前为止,还没有一个具有足够说服力的用例将它们包含在语言中
解决方法通常是反转将导致执行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
这已经足够清楚了,而且通常不会成为负担,除非您有一系列精细的剔除来控制循环操作。:
我们对“继续”的主要担忧是,在我们看来,还有一些其他控制结构或多或少与“继续”同等重要,甚至可能取代它。(例如,与标签(如Java中的)或更通用的goto决裂。)“continue”似乎并不比其他控制结构机制更特殊,只是它存在于更多的语言中。(Perl实际上有两个“continue”语句,“next”和“redo”。这两个语句都很有用。)
如前所述,第一部分在本文中得到了回答
至于解决方法,您可以将循环体包装在函数中,然后尽早返回,例如
-- 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
或者,如果您同时需要中断
和继续
功能,请让本地功能执行测试,例如:
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
同样,对于反转,您可以简单地使用以下代码:
for k,v in pairs(t) do
if not isstring(k) then
-- do something to t[k] when k is not a string
end
在Lua5.2中,最好的解决方法是使用goto:
——打印[|1,10 |]中的奇数
对于i=1,10 do
如果i%2==0,则转到继续结束
印刷品(一)
::继续::
结束
从2.0.1版开始,LuaJIT就支持这一点。您可以在附加的中包装循环体,重复直到为true,然后在内部使用do break end
以实现继续的效果。当然,如果您还打算真正地中断循环,则需要设置额外的标志
这将循环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
$luac-l continue.lua
主(22条指令,0x23c9530处88字节)
0+参数,6个插槽,0个上限值,4个局部变量,6个常量,0个函数
1[1]荷载K 0-1;1.
2[1]荷载K 1-2;3.
3[1]荷载K 2-1;1.
4[1]为0 16;到21岁
5[3]GETGLOBAL 4-3;打印
6[3]荷载K 5-1;1.
7[3]致电4 2 1
8[4]GETGLOBAL 4-3;打印
9[4]荷载K 5-4;2.
10[4]致电4 2 1
11[5]GETGLOBAL 4-3;打印
12[5]荷载K 5-2;3.
13[5]致电4 2 1
14[6]jmp6;到21号--给你!若从代码中删除do break end,结果将只相差这一行。
15[7]GETGLOBAL 4-3;打印
16[7]荷载K 5-5;4.
17[7]致电4 2 1
18[8]GETGLOBAL 4-3;打印
19[8]荷载K 5-6;5.
20[8]致电4 2 1
21[1]用于循环0-17;至5
22[10]返回0 1
我们可以如下实现,它将跳过偶数
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:
我们多次遇到这种情况,只需使用一个标志来模拟“继续”。我们也尽量避免使用goto语句
示例:代码打算打印从i=1到i=10的语句,i=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
通过使用测试标志封闭所有剩余语句,直到循环的结束范围
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
我并不是说这是最好的方法,但它对我们非常有效。为什么没有继续?
因为它是不必要的。很少有开发人员需要它的情况
A) 当你有一个非常简单的循环时,比如说一个1行或2行的循环,那么你只需要改变循环条件,它仍然是可读的
B) 当你编写简单的过程代码(又名,我们在上个世纪如何编写代码)时,你也应该应用结构化编程(又名,我们在上个世纪如何编写更好的代码)
C) 如果您正在编写面向对象的代码,那么循环体应该由不超过一个或两个方法调用组成,除非它可以用一个或两个线性函数表示(在这种情况下,请参阅a)
D) 如果您正在编写函数代码,只需为下一次迭代返回一个简单的尾部调用
只有在这种情况下,您才需要使用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
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