Pourquoi Lua n’a-t-il pas de déclaration “continue”?

J’ai beaucoup travaillé avec Lua ces derniers mois et j’aime vraiment la plupart des fonctionnalités, mais il me manque encore quelque chose parmi celles-ci:

  • Pourquoi n’y a-t-il pas de continue ?
  • Quelles solutions de contournement existe-t-il?

La façon dont le langage gère la scope lexicale crée des problèmes d’inclusion à la fois du goto et du 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 local a à l’intérieur du corps de la boucle masque la variable externe nommée a et la scope de ce local s’étend à travers la condition de l’instruction till de sorte que la condition teste le plus profond a .

Si continue existait, il devrait être restreint sémantiquement pour être seulement valide après que toutes les variables utilisées dans la condition soient entrées dans la scope. 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 simple réponse de refus de continue avec la repeat ... until style de boucle. Jusqu’à présent, aucun cas d’utilisation suffisamment convaincant n’a été présenté pour les inclure dans la langue.

Le travail consiste généralement à inverser la condition à l’origine de l’exécution continue et à collecter le rest 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 isssortingng(k) then continue end -- do something to t[k] when k is not a ssortingng end 

pourrait être écrit

 -- valid Lua 5.1 (or 5.2) for k,v in pairs(t) do if not isssortingng(k) then -- do something to t[k] when k is not a ssortingng end end 

C’est assez clair, et généralement pas un fardeau à moins que vous ayez une série de rejets élaborés qui contrôlent le fonctionnement de la boucle.

Dans Lua 5.2, la meilleure solution consiste à 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 supporté dans LuaJIT depuis la version 2.0.1

Vous pouvez envelopper le corps de la boucle dans une repeat until true supplémentaire repeat until true , puis utiliser ” do break end pour continuer. Naturellement, vous devrez configurer des indicateurs supplémentaires si vous souhaitez également sortir de la boucle.

Cela se bouclera 5 fois, en 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 en littéral un opcode JMP en bytecode Lua!

 $ luac -l continue.lua main  (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 

La première partie reçoit une réponse dans la FAQ, comme indiqué.

Comme pour une solution de contournement, vous pouvez envelopper le corps de la boucle dans une fonction et return tôt, 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 fonctionnalités de break et de continue , la fonction locale doit effectuer le test, 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 

Directement du designer de Lua lui – même :

Notre principale préoccupation avec “continue” est qu’il existe plusieurs autres structures de contrôle qui (à notre avis) sont plus ou moins importantes que “continue” et peuvent même la remplacer. (Par exemple, la rupture avec les labels [comme en Java] ou même un goto plus générique.) “Continue” ne semble pas plus spécial que les autres mécanismes de structure de contrôle, sauf qu’il est présent dans plus de langues. (Perl a en fait deux instructions “continue”, “next” et “redo”. Les deux sont utiles.)

Je n’ai jamais utilisé Lua auparavant, mais je l’ai googlé et j’ai trouvé ceci:

http://www.luafaq.org/

Vérifiez la question 1.26 .

Ceci est une plainte commune. Les auteurs de Lua ont estimé que continuer n’était que l’un des nombreux mécanismes de stream de contrôle possibles (le fait qu’il ne puisse pas fonctionner avec les règles de scope de répétition / jusqu’à était un facteur secondaire).

Dans Lua 5.2, il existe une instruction goto qui peut être facilement utilisée pour faire le même travail.

Avec l’inversion, vous pouvez simplement utiliser le code suivant:

 for k,v in pairs(t) do if not isssortingng(k) then -- do something to t[k] when k is not a ssortingng end 

Nous pouvons y arriver comme ci-dessous, il sautera des nombres pairs

 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 

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 nombres de 1 à 10 sauf 3. En outre, il imprime également “loop start”, loop end “,” if start “et” if end “pour simuler d’autres instructions qui existent dans votre code et déclarations nestedes.

 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 incluant toutes les instructions restantes jusqu’à la fin 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.