Pourquoi Lua n'a pas de déclaration" continue"?

J'ai beaucoup travaillé avec Lua au cours des derniers mois, et j'aime vraiment la plupart des fonctionnalités, mais je manque encore quelque chose parmi celles-ci:

  • pourquoi n'y a-t-il pas de continue ?
  • quelles solutions de rechange y a-t-il?
116
demandé sur finnw 2010-08-19 22:24:53

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.

61
répondu RBerteig 2012-11-01 18:02:23

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

59
répondu catwell 2013-04-01 20:56:32

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
35
répondu Oleg V. Volkov 2012-12-11 17:20:54

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.)

15
répondu Stuart P. Bentley 2011-05-24 18:03:24

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
15
répondu finnw 2017-05-23 11:54:47

Je n'ai jamais utilisé Lua avant, mais je L'ai googlé et est venu avec ceci:

http://www.luafaq.org /

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.

7
répondu slain 2016-07-23 14:59:14

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
4
répondu Dilip 2014-09-11 07:06:46

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
3
répondu 8lakester 2012-10-16 22:10:54

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.

3
répondu winux 2016-08-03 08:30:35