J'ai beaucoup traité avec Lua ces derniers mois et j'aime beaucoup la plupart des fonctionnalités, mais il me manque encore quelque chose parmi celles-ci:
continue
?La façon dont le langage gère l'étendue lexicale crée des problèmes en incluant à 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 local a
à l'intérieur du corps de la boucle masque la variable externe nommée a
, et la portée de cette locale s'étend à travers la condition de l'instruction until
de sorte que la condition teste la plus intime a
.
Si continue
existait, il devrait être restreint sémantiquement pour n'être valide que lorsque toutes les variables utilisées dans la condition sont entrées dans la portée. C'est une condition difficile à documenter à l'utilisateur et à appliquer dans le compilateur. Diverses propositions ont été examinées autour de cette question, notamment la simple réponse consistant à interdire continue
avec le repeat ... until
style de boucle. Jusqu'à présent, personne n'a eu de cas d'utilisation suffisamment convaincant pour les inclure dans le langage.
La solution consiste généralement à inverser la condition qui entraînerait l'exécution de continue
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
Cela est assez clair et ne constitue généralement pas un fardeau, à moins que vous ne disposiez d’une série d’éléments de sélection é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é par LuaJIT depuis la version 2.0.1
Vous pouvez envelopper le corps de la boucle dans repeat until true
Supplémentaire, puis utiliser do break end
À l'intérieur pour l'effet de continuer. Naturellement, vous aurez besoin de mettre en place des drapeaux supplémentaires si vous avez également l'intention de vraiment break
en boucle.
Cela fera une boucle 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 traduit même un opcode littéral JMP
en 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
La première partie reçoit une réponse dans le FAQ comme tué signalé.
En ce qui concerne une solution de contournement, vous pouvez envelopper le corps de la boucle dans une fonction et return
à partir 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 souhaitez utiliser les fonctionnalités break
et continue
, faites effectuer le test à 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
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 aussi importantes que "continue" et peuvent même la remplacer. (Par exemple, une rupture avec des étiquettes [comme en Java] ou même une 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 plusieurs langues. (Perl a en fait deux instructions "continue", "next" et "refaire". Les deux sont utiles.)
Je n'avais jamais utilisé Lua auparavant, mais je l'ai googlé et j'ai trouvé ceci:
Vérifiez question 1.26 .
Ceci est une plainte commune. Les auteurs de Lua ont estimé que la poursuite n'était qu'un des nombreux nouveaux mécanismes de flux de contrôle possibles (le fait qu'elle ne puisse pas fonctionner avec les règles de champ de répétition/jusqu'à était un facteur secondaire.)
Dans Lua 5.2, il existe une déclaration goto qui peut facilement être 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 déclarations goto.
Exemple: Le code a l'intention d'imprimer les déclarations 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 présentes 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 obtenu en incluant 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.
Nous pouvons le réaliser 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
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