Pular para o conteúdo principal

Break, continue, labels e goto

7 min de leitura•Arquivado emLinguagem de Programação Goem

Aprenda a controlar o fluxo de loops em Go com break e continue, como labels os estendem para loops aninhados, e onde o goto se encaixa — e quando evitá-lo.

Controlando o fluxo dentro de loops

Loops raramente executam do início ao fim sem nenhuma intervenção. Programas reais precisam sair cedo quando uma correspondência é encontrada, pular iterações que não atendem a uma condição, ou sair de loops profundamente aninhados em um único movimento. Go fornece quatro constructs para isso: break, continue, goto e labels.

Este artigo cobre cada um em profundidade — o que fazem, onde são genuinamente úteis, e onde devem ser evitados.

O statement break

break termina o for loop mais interno imediatamente. A execução continua com o código que vem após o loop.

O loop normalmente executaria dez vezes, mas no momento em que i é igual a 5 o break é disparado e o loop termina. O fmt.Println nessa iteração nunca executa, e tampouco as iterações restantes.

Simulando um loop do-while

Go não tem o construct do-while, mas break permite replicar o padrão. Um do-while executa o corpo pelo menos uma vez e verifica a condição no final. Aqui está o equivalente idiomático em Go:

O for loop infinito garante que o corpo execute pelo menos uma vez. A condição é testada no final usando if + break. Este é um padrão comum ao ler input do usuário ou fazer polling de um recurso.

O statement continue

continue pula o restante da iteração atual e avança diretamente para a próxima. O loop em si continua executando — apenas o passo atual é interrompido.

Quando i é par, continue volta para o cabeçalho do loop (i++, depois a verificação da condição). O fmt.Println só é alcançado para valores ímpares.

Isso é frequentemente mais limpo do que aninhar todo o corpo do loop dentro de um if. Compare:

Ambos são equivalentes, mas a versão com continue mantém o código do "caminho feliz" no nível superior e torna a condição de guarda explícita no início do corpo. Para corpos de loop longos, isso reduz o aninhamento e melhora a legibilidade.

Labels

Por padrão, break e continue afetam apenas o loop em que estão fisicamente inseridos. Quando você tem loops aninhados, essa limitação se torna um problema: se quiser sair do loop externo a partir do interno, um break simples não resolve.

Labels resolvem isso. Um label é um identificador seguido de dois-pontos, colocado imediatamente antes de um statement for:

Saída:

i=0 j=0
i=0 j=1
i=0 j=2
i=1 j=0

Quando i == 1 e j == 1, break outer sai do loop com label outer — não apenas do for interno. Sem o label, break só sairia do loop interno, e o loop externo continuaria a partir de i=1, j=2.

Labels funcionam de forma idêntica com continue:

Saída:

i=0 j=0
i=1 j=0
i=2 j=0

continue outer pula o restante do loop interno e avança a iteração do loop externo. Para cada valor de i, apenas j=0 é impresso — assim que j chega a 1, o loop externo avança.

O statement goto

goto transfere o controle incondicionalmente para um statement com label em qualquer outra parte da mesma função. Ao contrário de break e continue — que só interagem com loops — goto pode pular para qualquer ponto com label no corpo da função.

Isso imprime de 0 a 4. O goto loop volta para o label loop:, reavaliando a condição do if a cada passo. O efeito é o mesmo que um for loop, apenas escrito de forma mais indireta.

Restrições sobre goto

Go impõe duas restrições rígidas ao goto para evitar os tipos mais perigosos de saltos:

1. Não é permitido pular sobre uma declaração de variável.

Se isso fosse permitido, x estaria no escopo em end: mas nunca teria sido inicializado, levando ao uso de uma variável não inicializada.

2. Não é permitido pular para dentro de um bloco interno ou do mesmo nível.

Pular para dentro de um bloco ignoraria a inicialização de qualquer variável declarada no início desse bloco.

Quando goto é (raramente) apropriado

Em Go, goto praticamente não é usado em código de aplicação. O loop for, break e continue cobrem todas as necessidades de iteração. O caso de uso legítimo mais comum aparece em código de baixo nível ou gerado, onde uma estrutura plana com saltos explícitos é mais eficiente ou mais fácil de produzir do que um loop estruturado.

Resumo

StatementEscopoEfeito
breakLoop ou switch mais internoSai imediatamente
break labelLoop nomeado pelo labelSai daquele loop específico
continueLoop mais internoPula para a próxima iteração
continue labelLoop nomeado pelo labelPula para a próxima iteração daquele loop
goto labelQualquer label na mesma funçãoSalta incondicionalmente para aquele label

break e continue são ferramentas do dia a dia — use-os livremente para manter os corpos de loop planos e legíveis. Labels são válidos, mas incomuns; recorra a eles quando loops aninhados genuinamente precisam de controle entre níveis. goto quase nunca é a escolha certa em código de aplicação; se você se pegar escrevendo-o, dê um passo atrás e reconsidere a estrutura da sua função.