while pairs loop language for extension loops lua language-design

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:

http://www.luafaq.org/

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).