Respuestas:
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
continue
día real . El goto
reemplazo no se ve muy bien y necesita más líneas. Además, ¿no crearía problemas si tuviera más de un ciclo haciendo esto en una función, ambas con ::continue::
? Inventar un nombre por ciclo no suena como algo digno de hacer.
La forma en que el lenguaje gestiona el alcance léxico crea problemas al incluir ambos goto
y 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 local a
dentro del cuerpo del bucle enmascara la variable externa nombrada a
, y el alcance de ese local se extiende a través de la condición de la until
declaración, por lo que la condición está probando lo más interno a
.
Si continue
existiera, 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 al usuario y aplicar en el compilador. Se han discutido varias propuestas sobre este tema, incluida la respuesta simple de no permitir continue
con el repeat ... until
estilo de bucle. Hasta el momento, ninguno ha tenido un caso de uso suficientemente convincente para incluirlos en el idioma.
La solución general es invertir la condición que haría continue
que se ejecute a, y recolectar el resto del cuerpo del bucle bajo 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 ser escrito
-- 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 generalmente no es una carga a menos que tenga una serie de sacrificios elaborados que controlan la operación del bucle.
until...
.
goto
en Lua 5.2. Naturalmente, goto
tiene el mismo problema. Finalmente, decidieron que, independientemente de los costos de tiempo de ejecución y / o generación de código que protegieran, valía la pena tener los beneficios de tener una flexibilidad goto
que se pueda utilizar para emular tanto continue
a nivel múltiple como a nivel múltiple break
. Tendría que buscar en los archivos de la lista Lua los hilos relevantes para obtener los detalles. Como lo presentaron goto
, obviamente no era insuperable.
local
es una directiva solo del compilador, no importa qué instrucciones de tiempo de ejecución se encuentren local
y el uso variable, no necesita cambiar nada en el compilador para mantener el mismo comportamiento de alcance. Sí, esto podría no ser tan obvio y necesitará documentación adicional, pero, para reiterar nuevamente, requiere CERO cambios en el compilador. repeat do break end until true
ejemplo en mi respuesta ya genera exactamente el mismo código de bytes que el compilador continuaría, la única diferencia es que con continue
usted no necesitaría una sintaxis extra fea para usarlo.
do{int i=0;}while (i == 0);
falla, o en C ++: do int i=0;while (i==0);
también falla ("no se declaró en este ámbito"). Demasiado tarde para cambiar eso ahora en Lua, desafortunadamente.
Puede envolver el cuerpo del bucle en adicional repeat until true
y luego usarlo do break end
dentro para continuar. Naturalmente, necesitará configurar banderas adicionales si también tiene la intención de break
salir del 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 se traduce en un código JMP
de operación literal en Lua bytecode!
$ 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
resultados en SO! Tenga un
Directamente del diseñador del propio Lua :
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).
continue
en Lua, lo siento".
La primera parte se responde en las preguntas frecuentes como se señaló como asesinado .
En cuanto a una solución alternativa, puede envolver el cuerpo del bucle en una función y return
desde el principio, p. Ej.
-- 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 ambas break
y continue
funcionalidad, haga que la función local realice la prueba, p. 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
collectgarbage("count")
incluso después de sus simples 100 intentos y luego hablaremos. Tal optimización "prematura" evitó que un proyecto de alta carga se reiniciara cada minuto la semana pasada.
Nunca he usado Lua antes, pero lo busqué en Google y se me ocurrió esto:
Verifique la pregunta 1.26 .
Esta es una queja común. Los autores de Lua consideraron que continuar era solo uno de una serie de posibles nuevos mecanismos de control de flujo (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 instrucción goto que se puede usar fácilmente para hacer el mismo trabajo.
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 tiene la intención de imprimir las declaraciones de i = 1 a i = 10 excepto i = 3. Además, también imprime "loop start", loop end "," if start "y" if end "para simular otras instrucciones anidadas que existen en su código.
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 encerrando todas las declaraciones restantes hasta el alcance final del bucle 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 perfectamente.
Lua es un lenguaje de script ligero que quiere ser lo más pequeño posible. Por ejemplo, muchas operaciones unarias como el incremento previo / posterior no están disponibles
En lugar de continuar, puedes usar 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
De nuevo con la inversión, simplemente puede 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
Porque es innecesario¹. Hay muy pocas situaciones en las que un desarrollador lo necesite.
A) Cuando tiene un bucle muy simple, diga una línea de 1 o 2 líneas, entonces puede cambiar la condición del bucle y todavía es bastante legible.
B) Cuando está escribiendo un código de procedimiento simple (también conocido como cómo escribimos código en el siglo pasado), también debería estar aplicando una programación estructurada (también conocido como cómo escribimos un código mejor en el siglo pasado)
C) Si está escribiendo código orientado a objetos, su cuerpo de bucle debe consistir en no más de una o dos llamadas de método a menos que pueda expresarse en una o dos líneas (en cuyo caso, consulte A)
D) Si está escribiendo código funcional, simplemente devuelva una llamada simple para la próxima iteración.
El único caso en el que desea utilizar una continue
palabra clave es si desea codificar Lua como si fuera python, que simplemente no lo es.
A menos que se aplique A), en cuyo caso no hay necesidad de ninguna solución alternativa, debe estar haciendo una programación estructurada, orientada a objetos o funcional. Esos son los paradigmas para los que Lua fue creado, por lo que estarías luchando contra el idioma si te esfuerzas por evitar sus patrones.
Alguna aclaración:
¹ Lua es un lenguaje muy minimalista. Intenta tener la menor cantidad de características posibles, y una continue
declaración no es una característica esencial en ese sentido.
Creo que esta filosofía del minimalismo es bien captada por Roberto Ierusalimschy en esta entrevista de 2019 :
agregue eso y eso y eso, apague eso, y al final entendemos que la conclusión final no satisfará a la mayoría de las personas y no pondremos todas las opciones que todos quieren, por lo que no ponemos nada. Al final, el modo estricto es un compromiso razonable.
² Parece que hay una gran cantidad de programadores que vienen a Lua desde otros idiomas porque cualquier programa para el que están tratando de escribir los usa, y muchos de ellos quieren no parecen querer escribir nada más que su idioma de elección, lo que lleva a muchas preguntas como "¿Por qué Lua no tiene la función X?"
Matz describió una situación similar con Ruby en una entrevista reciente :
La pregunta más popular es: "Soy de la comunidad del lenguaje X; ¿no puedes presentarle una característica del lenguaje X a Ruby?", O algo así. Y mi respuesta habitual a estas solicitudes es ... "no, no haría eso", porque tenemos un diseño de lenguaje diferente y políticas de desarrollo de lenguaje diferentes.
³ Hay algunas maneras de hackear esto; algunos usuarios han sugerido usar goto
, lo cual es una aproximación lo suficientemente buena en la mayoría de los casos, pero se pone muy feo muy rápidamente y se rompe completamente con bucles anidados. El uso de goto
s también lo pone en peligro de recibir una copia de SICP cada vez que muestra su código a otra persona.
continue
podría ser una característica conveniente, pero eso no lo hace necesario . Mucha gente usa Lua bien sin él, por lo que realmente no hay razón para que sea otra cosa que una característica ordenada que no es esencial para ningún lenguaje de programación.
goto
declaración que puede usarse para implementar continuar. Ver las respuestas a continuación.