loops - loop - lua pairs
¿Por qué Lua no tiene una declaración de "continuación"? (9)
En Lua 5.2 la mejor solución es usar goto:
-- prints odd numbers in [|1,10|]
for i=1,10 do
if i % 2 == 0 then goto continue end
print(i)
::continue::
end
Esto es compatible con LuaJIT desde la versión 2.0.1
He estado lidiando mucho con Lua en los últimos meses, y realmente me gustan la mayoría de las funciones, pero todavía me falta algo entre ellas:
- ¿Por qué no hay
continue
? - ¿Qué soluciones hay para eso?
La forma en que el lenguaje gestiona el alcance léxico crea problemas al incluir tanto goto
como continue
. Por ejemplo,
local a=0
repeat
if f() then
a=1 --change outer a
end
local a=f() -- inner a
until a==0 -- test inner a
La declaración de a local a
dentro del cuerpo de bucle enmascara la variable externa denominada a
, y el alcance de ese local se extiende a través de la condición de la instrucción until
para que la condición pruebe la a más interna.
Si continue
existiendo, tendría que restringirse semánticamente para que solo sea válido después de que todas las variables utilizadas en la condición hayan entrado en el alcance. Esta es una condición difícil de documentar para el usuario y hacer cumplir en el compilador. Se han discutido varias propuestas sobre este tema, incluida la respuesta simple de no permitir continue
con la repeat ... until
estilo del ciclo. Hasta ahora, ninguno ha tenido un caso de uso suficientemente convincente para incluirlos en el lenguaje.
La solución alternativa es invertir la condición que provocaría que se continue
ejecutando, y recopilar el resto del cuerpo del bucle en esa condición. Entonces, el siguiente ciclo
-- 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
podría escribirse
-- 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
Es lo suficientemente claro, y por lo general no es una carga a menos que tenga una serie de recortes elaborados que controlan la operación de bucle.
La primera parte se responde en las FAQ como se señala.
En cuanto a una solución alternativa, puede envolver el cuerpo del bucle en una función y return
temprano a partir de eso, por ejemplo
-- 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
O si desea la funcionalidad break
y continue
, haga que la función local realice la prueba, por ej.
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
Nos encontramos con este escenario muchas veces y simplemente usamos una bandera para simular continuar. Tratamos de evitar el uso de declaraciones goto también.
Ejemplo: el código intenta imprimir los números del 1 al 10, excepto 3. Además, también imprime "inicio de bucle", final de bucle "," si inicio "y" si finaliza "para simular otras declaraciones que existen en su código y declaraciones anidadas.
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
se logra al encerrar todas las declaraciones restantes hasta el alcance final del ciclo con un indicador de prueba.
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
No digo que este sea el mejor enfoque, pero nos funciona a la perfección.
Nuevamente con la inversión, simplemente podría usar el siguiente código:
for k,v in pairs(t) do
if not isstring(k) then
-- do something to t[k] when k is not a string
end
Nunca antes había usado Lua, pero busqué en Google y se me ocurrió esto:
Ver FAQ .
Esta es una queja común. Los autores de Lua consideraron que continuar era solo uno de los posibles nuevos mecanismos de flujo de control (el hecho de que no puede funcionar con las reglas de alcance de repetir / hasta que fue un factor secundario).
En Lua 5.2, hay una declaración goto que se puede usar fácilmente para hacer el mismo trabajo.
Podemos lograrlo de la siguiente manera, omitirá los números pares
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
Puede envolver el cuerpo del bucle en repeat until true
adicional repeat until true
y luego usar do break end
inside para el efecto de continuar. Naturalmente, tendrá que configurar indicadores adicionales si también tiene la intención de break
realmente el ciclo.
Esto se repetirá 5 veces, imprimiendo 1, 2 y 3 cada vez.
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
¡Esta construcción incluso traduce literalmente un código de operación JMP
en el bytecode de Lua!
$ 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
Directamente del diseñador de Lua mismo :
Nuestra principal preocupación con "continuar" es que hay varias otras estructuras de control que (en nuestra opinión) son más o menos tan importantes como "continuar" e incluso pueden reemplazarlo. (Por ejemplo, romper con etiquetas [como en Java] o incluso un goto más genérico.) "Continuar" no parece más especial que otros mecanismos de estructura de control, excepto que está presente en más idiomas. (Perl en realidad tiene dos declaraciones "continuar", "siguiente" y "rehacer". Ambas son útiles).