Pourquoi Lua n'a pas de déclaration" continue"?
9 réponses
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 local a
à l'intérieur du corps de boucle masque la variable externe nommée a
, et la portée de cette locale s'étend à travers la condition de la déclaration until
de sorte que la condition est l'essai le plus interne a
.
si continue
existait, il serait doivent être restreintes sémantiquement pour être valide uniquement après que toutes les variables utilisées dans l'état de venir dans l'étendue. C'est une condition difficile à document à l'utilisateur et l'appliquer dans le compilateur. Diverses propositions sur cette question ont été discutées, y compris la simple réponse de rejeter continue
avec le style de boucle repeat ... until
. Jusqu'à présent, aucun n'a suffisamment convaincante de cas d'utilisation pour obtenir inclus dans la langue.
le travail autour est généralement d'inverser la condition qui entraînerait l'exécution d'un continue
, et de collecter le reste du corps de boucle dans cette condition. Ainsi, 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 ayez une série de coupes complexes qui contrôlent le fonctionnement de la boucle.
en Lua 5.2 la meilleure solution 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 supporté dans LuaJIT depuis la version 2.0.1
vous pouvez envelopper le corps de boucle en repeat until true
supplémentaire et ensuite 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
hors de boucle ainsi.
ce sera boucle 5 fois, l'impression 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 à la lettre un opcode JMP
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
directement du créateur 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, rompez avec les étiquettes [comme en Java] ou même avec 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 "continuer", "suivant" et "redo". Les deux sont utiles.)
la première partie est répondue dans le FAQ comme tué a souligné.
comme pour une solution de contournement, vous pouvez envelopper le corps de la boucle dans une fonction et return
tôt 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 fonctionnalités break
et continue
, demandez à la fonction locale d'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
Je n'ai jamais utilisé Lua avant, mais je L'ai googlé et est venu avec ceci:
Vérifier question 1.26 .
C'est une plainte fréquente. Les auteurs de L'Arus ont estimé que continue n'était qu'un des nombreux nouveaux mécanismes possibles de contrôle du débit (le fait qu'il ne puisse pas fonctionner avec les règles de portée de repeat/until était un facteur secondaire).)
dans Lua 5.2, il y a une instruction goto qui peut être facilement utilisée pour faire le même travail.
nous pouvons l'atteindre comme ci-dessous, il va sauter 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
Nous avons rencontré ce scénario plusieurs fois et nous utilisons simplement un drapeau pour simuler continuer. Nous essayons d'éviter l'utilisation de goto.
exemple: le code a l'intention d'imprimer les nombres de 1 à 10 sauf 3. En outre, il imprime également "loop start", "if start", et "if end" pour simuler d'autres instructions qui existent dans votre code et les instructions imbriquées.
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 joignant toutes les déclarations restantes jusqu'à la fin de la boucle avec un drapeau 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 il fonctionne parfaitement pour nous.