171 votes

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 continue ?
  • Quelles solutions de contournement existe-t-il?

103voto

catwell Points 3193

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

74voto

RBerteig Points 23331

La façon dont la langue gère le domaine lexical crée des problèmes avec notamment les deux 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 d' local a à l'intérieur du corps de la boucle des masques à l'extérieur variable nommée a, et la portée de ce local s'étend sur l'état de l' until déclaration si la condition est tests les plus intimes a.

Si continue existait, il devrait être limité du point de vue sémantique 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. Différentes propositions autour de cette question ont été abordés, y compris la réponse la plus simple de interdisez continue avec l' repeat ... until style de boucle. Jusqu'à présent, aucun n'a suffisamment convaincante de cas d'utilisation pour obtenir inclus dans la langue.

Le travail autour de est généralement pour inverser la condition qui entraîne un continue à être exécutée, et de recueillir le reste du corps de la boucle en vertu de 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

peut être écrite

-- 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, sauf si vous avez une série de complexe de rebuts qui contrôle le fonctionnement en boucle.

60voto

Oleg V. Volkov Points 9724

Vous pouvez envelopper le corps de la boucle dans repeat until true supplémentaire, puis utiliser do break end inside pour obtenir l'effet de continuer. Bien sûr, vous aurez besoin de mettre en place des drapeaux supplémentaires si vous avez l' intention aussi vraiment break de la boucle ainsi.

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 en un seul opcode JMP dans le 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
 

19voto

Stuart P. Bentley Points 2705

Directement à partir du concepteur de Lua lui-même:

Notre principale préoccupation avec "continuer" est qu'il y a plusieurs autres structures de contrôle qui (à notre avis) sont plus ou moins aussi important que "continuer" et peut même se substituer à elle. (E. g., rompre avec étiquettes [comme en Java] ou même un plus générique goto.) "continuer", ne semble pas plus spécial que les autres le contrôle de la structure des mécanismes, sauf qu'il est présent dans plus de langues. (Perl a en fait deux "continuer", "suivant" et "redo". Les deux sont utiles.)

17voto

finnw Points 24592

La première partie de réponse dans la FAQ comme immolé souligné.

Comme pour une solution de contournement, vous pouvez envelopper le corps de la boucle dans une fonction, et return au début de celle, 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 break et continue fonctionnalités, que la fonction d'effectuer le test, par ex.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X