web-dev-qa-db-fra.com

Pourquoi Lua n'a-t-il aucune déclaration "continuer"?

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:

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

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.

64
RBerteig

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

64
catwell

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
38
Oleg V. Volkov

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
16
finnw

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

15

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

http://www.luafaq.org/

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.

8
slain

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.

5
winux

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
5
Dilip

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
8lakester