Réponses:
Dans Lua 5.2, la meilleure solution de contournement est d'utiliser goto:
-- prints odd numbers in [|1,10|]
for i=1,10 do
if i % 2 == 0 then goto continue end
print(i)
::continue::
end
Ceci est pris en charge dans LuaJIT depuis la version 2.0.1
continue
jour réel . Le goto
remplacement n'a pas l'air très beau et a besoin de plus de lignes. De plus, cela ne créerait-il pas de problèmes si vous aviez plus d'une boucle faisant cela dans une fonction, les deux avec ::continue::
? Créer un nom par boucle ne semble pas être une bonne chose à faire.
La façon dont le langage gère la portée lexicale crée des problèmes avec l'inclusion à la fois goto
et continue
. Par exemple,
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 déclaration de l' local a
intérieur du corps de la boucle masque la variable externe nommée a
, et la portée de ce local s'étend à travers la condition de l' until
instruction afin que la condition teste la plus interne a
.
S'il continue
existait, il devrait être restreint sémantiquement pour n'être valide qu'une fois que toutes les variables utilisées dans la condition sont entrées dans la portée. C'est une condition difficile à documenter pour l'utilisateur et à appliquer dans le compilateur. Diverses propositions autour de cette question ont été discutées, y compris la réponse simple de refuser continue
avec le repeat ... until
style de boucle. Jusqu'à présent, aucun n'a eu de cas d'utilisation suffisamment convaincant pour les inclure dans le langage.
Le contournement consiste généralement à inverser la condition qui entraînerait continue
l'exécution d'un et à collecter le reste du corps de la boucle dans cette condition. Donc, la boucle suivante
-- 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
pourrait être écrit
-- 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
C'est assez clair et généralement pas un fardeau à moins que vous n'ayez une série d'abattages élaborés qui contrôlent l'opération de boucle.
until...
.
goto
dans Lua 5.2. Naturellement, goto
a le même problème. Ils ont finalement décidé que quels que soient les coûts d'exécution et / ou de génération de code à protéger, cela valait la peine d'avoir un flexible goto
qui peut être utilisé pour émuler à la fois continue
et à plusieurs niveaux break
. Vous devrez rechercher les archives de la liste Lua pour les fils pertinents pour obtenir les détails. Puisqu'ils l'ont introduit goto
, ce n'était évidemment pas insurmontable.
local
est une directive réservée au compilateur - peu importe les insructions d'exécution entre l' local
utilisation des variables et l'utilisation des variables - vous n'avez pas besoin de changer quoi que ce soit dans le compilateur pour conserver le même comportement de portée. Oui, cela n'est peut-être pas si évident et nécessite une documentation supplémentaire, mais, pour le répéter, cela nécessite des modifications ZERO dans le compilateur. repeat do break end until true
exemple dans ma réponse génère déjà exactement le même bytecode que le compilateur continuerait, la seule différence est qu'avec continue
vous n'auriez pas besoin de syntaxe supplémentaire laide pour l'utiliser.
do{int i=0;}while (i == 0);
échoue, ou en C ++: do int i=0;while (i==0);
échoue également ("n'a pas été déclaré dans cette portée"). Trop tard pour changer cela maintenant à Lua, malheureusement.
Vous pouvez envelopper le corps de la boucle en plus repeat until true
, puis l'utiliser à l' do break end
intérieur pour continuer. Naturellement, vous devrez configurer des indicateurs supplémentaires si vous avez également l'intention de vraiment vous break
déconnecter.
Cela fera une boucle 5 fois, imprimant 1, 2 et 3 à chaque fois.
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
Cette construction se traduit même par un opcode littéral JMP
dans le bytecode 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
luac
résultats sur SO! Avoir un vote positif bien mérité :)
Directement du créateur de Lua lui - même :
Notre principale préoccupation avec «continuer» est qu'il existe plusieurs autres structures de contrôle qui (à notre avis) sont plus ou moins aussi importantes que «continuer» et peuvent même le remplacer. (Par exemple, rompre avec les étiquettes [comme en Java] ou même un goto plus générique.) "Continuer" ne semble pas plus spécial que d'autres mécanismes de structure de contrôle, sauf qu'il est présent dans plus de langages. (Perl a en fait deux instructions "continue", "next" et "redo". Les deux sont utiles.)
continue
en Lua, désolé."
La première partie est répondue dans la FAQ comme l'a souligné tué .
En ce qui concerne une solution de contournement, vous pouvez envelopper le corps de la boucle dans une fonction et au return
début de cela, par exemple
-- 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
Ou si vous voulez les deux break
et la continue
fonctionnalité, faites effectuer le test par la fonction locale, par exemple
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")
même après vos simples 100 essais et ensuite nous parlerons. Une telle optimisation "prématurée" a évité à un projet à forte charge de redémarrer chaque minute la semaine dernière.
Je n'ai jamais utilisé Lua auparavant, mais je l'ai googlé et j'ai trouvé ceci:
Vérifiez la question 1.26 .
C'est une plainte courante. Les auteurs de Lua ont estimé que continuer n'était que l'un des nombreux nouveaux mécanismes de contrôle de flux possibles (le fait qu'il ne puisse pas fonctionner avec les règles de portée de répétition / jusqu'à ce que ce soit un facteur secondaire).
Dans Lua 5.2, il existe une instruction goto qui peut être facilement utilisée pour faire le même travail.
Nous avons rencontré ce scénario plusieurs fois et nous utilisons simplement un drapeau pour simuler continuer. Nous essayons également d'éviter l'utilisation des instructions goto.
Exemple: Le code a l'intention d'imprimer les instructions de i = 1 à i = 10 sauf i = 3. En outre, il imprime également "début de boucle", fin de boucle "," si début "et" si fin "pour simuler d'autres instructions imbriquées qui existent dans votre code.
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
est réalisé en englobant toutes les instructions restantes jusqu'à la fin de la portée de la boucle avec un indicateur de test.
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
Je ne dis pas que c'est la meilleure approche, mais cela fonctionne parfaitement pour nous.
Lua est un langage de script léger qui se veut le plus petit possible. Par exemple, de nombreuses opérations unaires telles que l'incrément pré / post ne sont pas disponibles
Au lieu de continuer, vous pouvez utiliser goto comme
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
Encore une fois avec l'inversion, vous pouvez simplement utiliser le code suivant:
for k,v in pairs(t) do
if not isstring(k) then
-- do something to t[k] when k is not a string
end
Parce que c'est inutile¹. Il y a très peu de situations où un développeur en aurait besoin.
A) Lorsque vous avez une boucle très simple, disons un 1 ou 2 lignes, vous pouvez simplement inverser la condition de la boucle et elle est toujours très lisible.
B) Lorsque vous écrivez un code procédural simple (c'est-à-dire comment nous avons écrit du code au siècle dernier), vous devriez également appliquer une programmation structurée (c'est-à-dire comment nous avons écrit un meilleur code au siècle dernier)
C) Si vous écrivez du code orienté objet, le corps de votre boucle ne doit pas comporter plus d'un ou deux appels de méthode à moins qu'il ne puisse être exprimé en une ou deux lignes (dans ce cas, voir A)
D) Si vous écrivez du code fonctionnel, retournez simplement un appel de fin pour la prochaine itération.
Le seul cas où vous voudriez utiliser un continue
mot-clé est si vous voulez coder Lua comme si c'était python, ce qui n'est tout simplement pas²².
À moins que A) s'applique, auquel cas il n'y a pas besoin de solutions de contournement, vous devriez faire de la programmation structurée, orientée objet ou fonctionnelle. Ce sont les paradigmes pour lesquels Lua a été conçu, donc vous vous battrez contre le langage si vous faites tout votre possible pour éviter leurs modèles .³
Quelques précisions:
¹ Lua est un langage très minimaliste. Il essaie d'avoir aussi peu de fonctionnalités que possible, et une continue
déclaration n'est pas une caractéristique essentielle dans ce sens.
Je pense que cette philosophie du minimalisme est bien capturée par Roberto Ierusalimschy dans cette interview de 2019 :
ajoutez ceci et cela et cela, mettez cela dehors, et à la fin nous comprenons que la conclusion finale ne satisfera pas la plupart des gens et nous ne mettrons pas toutes les options que tout le monde veut, donc nous ne mettons rien. Au final, le mode strict est un compromis raisonnable.
² Il semble y avoir un grand nombre de programmeurs qui arrivent à Lua à partir d'autres langues parce que quel que soit le programme pour lequel ils essaient de créer un script, il l'utilise, et beaucoup d'entre eux ne semblent pas vouloir écrire autre chose que leur langue de choix, ce qui conduit à de nombreuses questions telles que "Pourquoi Lua n'a-t-il pas la fonctionnalité X?"
Matz a décrit une situation similaire avec Ruby dans une récente interview :
La question la plus populaire est: "Je suis de la communauté du langage X; ne pouvez-vous pas introduire une fonctionnalité du langage X à Ruby?", Ou quelque chose comme ça. Et ma réponse habituelle à ces demandes est… "non, je ne ferais pas ça", parce que nous avons différentes conceptions linguistiques et différentes politiques de développement linguistique.
³ Il existe plusieurs façons de contourner ce problème; certains utilisateurs ont suggéré d'utiliser goto
, ce qui est une approximation assez bonne dans la plupart des cas, mais devient très moche très rapidement et se rompt complètement avec des boucles imbriquées. L'utilisation de goto
s vous expose également au risque de voir une copie de SICP vous être envoyée chaque fois que vous montrez votre code à quelqu'un d'autre.
continue
peut être une fonctionnalité pratique, mais cela ne le rend pas nécessaire . Beaucoup de gens utilisent très bien Lua sans lui, donc il n'y a vraiment aucune raison pour que ce soit autre chose qu'une fonctionnalité intéressante qui n'est essentielle à aucun langage de programmation.
goto
déclaration qui peut être utilisée pour implémenter continue. Voir les réponses ci-dessous.