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
continue
um dia real . A goto
substituiçã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 goto
e 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 a
dentro do corpo do loop mascara a variável externa denominada a
e o escopo desse local se estende pela condição da until
instrução, para que a condição esteja testando o mais interno a
.
Se continue
existisse, 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 continue
o repeat ... until
estilo 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 continue
a 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...
.
goto
no Lua 5.2. Naturalmente, goto
tem 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 goto
que pode ser usado para emular os dois continue
e 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 local
e 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 true
Por exemplo, na minha resposta já gera exatamente o mesmo bytecode que o compilador continuaria, a única diferença é que continue
você 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 true
e, em seguida, usá-lo do break end
para efeito de continuar. Naturalmente, você precisará configurar sinalizadores adicionais se também quiser realmente break
ficar 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 JMP
no 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
luac
resultados 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.)
continue
Lua, 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 return
desde 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 break
e continue
funcionalidade, 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 continue
palavra-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 continue
declaraçã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 goto
s também coloca você em risco de ter uma cópia do SICP sempre que você mostra seu código a mais alguém.
continue
pode 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.
goto
declaração que pode ser usada para implementar continue. Veja as respostas abaixo.