Respostas:
No Lua 5.2, a melhor solução alternativa é usar goto:
-- prints odd numbers in [|1,10|]
for i=1,10 do
if i % 2 == 0 then goto continue end
print(i)
::continue::
end
Isso é suportado no LuaJIT desde a versão 2.0.1
continueum dia real . A gotosubstituição não parece muito agradável e precisa de mais linhas. Além disso, isso não criaria problemas se você tivesse mais de um loop fazendo isso em uma função, ambos com ::continue::? Criar um nome por loop não parece uma coisa decente.
A maneira como o idioma gerencia o escopo lexical cria problemas com a inclusão de ambos gotoe continue. Por exemplo,
local a=0
repeat
if f() then
a=1 --change outer a
end
local a=f() -- inner a
until a==0 -- test inner a
A declaração de local adentro do corpo do loop mascara a variável externa denominada ae o escopo desse local se estende pela condição da untilinstrução, para que a condição esteja testando o mais interno a.
Se continueexistisse, teria que ser restrito semanticamente para ser válido somente depois que todas as variáveis usadas na condição entrassem em escopo. Essa é uma condição difícil de documentar para o usuário e impor no compilador. Várias propostas em torno dessa questão foram discutidas, incluindo a resposta simples de desaprovar continueo repeat ... untilestilo do loop. Até o momento, nenhum teve um caso de uso suficientemente atraente para incluí-los no idioma.
A solução alternativa é geralmente inverter a condição que causaria continuea execução de um e coletar o restante do corpo do loop sob essa condição. Então, o seguinte loop
-- 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
poderia ser escrito
-- 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
É claro o suficiente, e geralmente não é um fardo, a menos que você tenha uma série de abates elaborados que controlam a operação do loop.
until....
gotono Lua 5.2. Naturalmente, gototem o mesmo problema. Eles finalmente decidiram que, independentemente do custo de tempo de execução e / ou de geração de código, os benefícios valiam por ter um sistema flexível gotoque pode ser usado para emular os dois continuee os vários níveis break. Você precisaria procurar nos arquivos da lista Lua os segmentos relevantes para obter os detalhes. Desde que eles introduziram goto, obviamente não era intransponível.
localé uma diretiva apenas para compilador - não importa quais são as instruções de tempo de execução locale o uso variável - você não precisa alterar nada no compilador para manter o mesmo comportamento de escopo. Sim, isso pode não ser tão óbvio e precisa de alguma documentação adicional, mas, para reiterar novamente, requer ZERO alterações no compilador. repeat do break end until truePor exemplo, na minha resposta já gera exatamente o mesmo bytecode que o compilador continuaria, a única diferença é que continuevocê não precisaria de uma sintaxe extra feia para usá-lo.
do{int i=0;}while (i == 0);falha ou em C ++: do int i=0;while (i==0);também falha ("não foi declarado neste escopo"). Tarde demais para mudar isso agora em Lua, infelizmente.
Você pode envolver o corpo do loop em adicional repeat until truee, em seguida, usá-lo do break endpara efeito de continuar. Naturalmente, você precisará configurar sinalizadores adicionais se também quiser realmente breakficar fora de loop.
Isso repetirá 5 vezes, imprimindo 1, 2 e 3 a cada vez.
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
Essa construção é traduzida literalmente em um opcode JMPno 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
luacresultados no SO! Tenha um
Diretamente do designer do próprio Lua :
Nossa principal preocupação com "continuar" é que existem várias outras estruturas de controle que (a nosso ver) são mais ou menos tão importantes quanto "continuar" e podem até substituí-lo. (Por exemplo, quebre os rótulos [como em Java] ou mesmo um goto mais genérico.) "Continue" não parece mais especial do que outros mecanismos da estrutura de controle, exceto que ele está presente em mais idiomas. (O Perl realmente tem duas instruções "continue", "next" e "refazer". Ambas são úteis.)
continueLua, desculpe".
A primeira parte é respondida no FAQ como morto fora pontudo.
Quanto a uma solução alternativa, você pode agrupar o corpo do loop em uma função e returndesde o início, por exemplo,
-- 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, se você deseja ambos breake continuefuncionalidade, faça com que a função local realize o teste, por exemplo
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
collectgarbage("count")mesmo após suas 100 tentativas simples e depois conversaremos. Essa otimização "prematura" salvou um projeto de alta carga da reinicialização a cada minuto na semana passada.
Eu nunca usei Lua antes, mas pesquisei no Google e criei isso:
Verifique a pergunta 1.26 .
Esta é uma reclamação comum. Os autores de Lua acharam que continue era apenas um dos vários possíveis mecanismos de controle de fluxo (o fato de não poder trabalhar com as regras de escopo de repetição / até era um fator secundário).
No Lua 5.2, há uma instrução goto que pode ser facilmente usada para fazer o mesmo trabalho.
Encontramos esse cenário muitas vezes e simplesmente usamos um sinalizador para simular a continuação. Tentamos evitar o uso de instruções goto também.
Exemplo: O código pretende imprimir as instruções de i = 1 a i = 10, exceto i = 3. Além disso, ele também imprime "loop start", loop end "," if start "e" if end "para simular outras instruções aninhadas que existem no seu código.
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
é alcançado colocando-se todas as instruções restantes até o escopo final do loop com um sinalizador de teste.
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
Não estou dizendo que essa é a melhor abordagem, mas funciona perfeitamente para nós.
Lua é uma linguagem de script leve que deseja menor quanto possível. Por exemplo, muitas operações unárias, como pré / pós incremento, não estão disponíveis
Em vez de continuar, você pode usar ir como
arr = {1,2,3,45,6,7,8}
for key,val in ipairs(arr) do
if val > 6 then
goto skip_to_next
end
# perform some calculation
::skip_to_next::
end
Novamente com a inversão, você pode simplesmente usar o seguinte código:
for k,v in pairs(t) do
if not isstring(k) then
-- do something to t[k] when k is not a string
end
Porque é desnecessário¹. Existem muito poucas situações em que um desenvolvedor precisaria.
A) Quando você tem um loop muito simples, digamos um liner de 1 ou 2, você pode simplesmente mudar a condição do loop e ainda assim é legível.
B) Ao escrever código processual simples (também conhecido como como escrevemos código no século passado), você também deve aplicar programação estruturada (também conhecido como como escrevemos melhor código no século passado)
C) Se você estiver escrevendo código orientado a objeto, seu corpo do loop deve consistir em não mais de uma ou duas chamadas de método, a menos que possa ser expresso em uma ou duas linhas (nesse caso, consulte A)
D) Se você estiver escrevendo código funcional, basta retornar uma chamada final simples para a próxima iteração.
O único caso em que você deseja usar uma continuepalavra-chave é codificar Lua como se fosse python, o que simplesmente não é.²
A menos que A) se aplique; nesse caso, não há necessidade de soluções alternativas, você deve estar fazendo programação estruturada, orientada a objetos ou funcional. Esses são os paradigmas para os quais Lua foi criada, então você estaria lutando contra a linguagem se se esforçar para evitar os padrões deles.³
Alguns esclarecimentos:
Lua é uma linguagem muito minimalista. Ele tenta ter o mínimo de recursos possível e uma continuedeclaração não é um recurso essencial nesse sentido.
Acho que essa filosofia do minimalismo é bem capturada por Roberto Ierusalimschy nesta entrevista de 2019 :
adicione isso e aquilo e aquilo, coloque isso para fora e, no final, entendemos que a conclusão final não satisfará a maioria das pessoas e não colocaremos todas as opções que todos desejarem, por isso não colocamos nada. No final, o modo estrito é um compromisso razoável.
² Parece haver uma grande quantidade de programadores chegando a Lua de outras linguagens, porque qualquer programa que eles estão tentando criar o script o usa, e muitos deles querem não parecem querer escrever outra coisa senão a linguagem deles. opção, o que leva a muitas perguntas como "Por que Lua não possui o recurso X?"
Matz descreveu uma situação semelhante com Ruby em uma entrevista recente :
A pergunta mais popular é: "Sou da comunidade do idioma X; você não pode introduzir um recurso do idioma X no Ruby?", Ou algo assim. E minha resposta usual para essas solicitações é ... "não, eu não faria isso", porque temos um design de linguagem diferente e políticas de desenvolvimento de linguagem diferentes.
³ Existem algumas maneiras de contornar isso; alguns usuários sugeriram o uso goto, o que é uma aproximação suficientemente boa na maioria dos casos, mas fica muito feio muito rapidamente e quebra completamente com loops aninhados. O uso de gotos também coloca você em risco de ter uma cópia do SICP sempre que você mostra seu código a mais alguém.
continuepode ser um recurso conveniente, mas isso não o torna necessário . Muitas pessoas usam Lua muito bem sem ele, então não há realmente nenhum caso de ser algo além de um recurso interessante que não é essencial para qualquer linguagem de programação.
gotodeclaração que pode ser usada para implementar continue. Veja as respostas abaixo.