Menu

Laço for em Golang: as quatro formas com exemplos

Go tem uma única palavra-chave de laço, for, e ela cobre tudo: o laço contador de três cláusulas, o laço só com condição (o while), o laço infinito e o range sobre slices, maps, strings, channels, inteiros e funções. Mais break e continue com label e a mudança nas variáveis de laço do Go 1.22.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Go tem exatamente uma palavra-chave de laço: for. Ela tem quatro formatos, e juntos eles cobrem todo laço que você escreveria com for, while, do while ou foreach em outras linguagens.

Não há parênteses em volta do cabeçalho do laço, e as chaves são sempre obrigatórias.

O laço de três cláusulas

for init; condition; post {
	// body
}
  1. init executa uma vez antes do laço. Normalmente é uma declaração curta de variável como i := 0, e essa variável só existe dentro do laço.
  2. condition é verificada antes de cada iteração. Quando é falsa, o laço termina.
  3. O corpo executa.
  4. post executa depois de cada iteração, normalmente i++.

i++ é uma instrução em Go, não uma expressão, então post não pode conter i++, j--. Use uma atribuição paralela: i, j = i+1, j-1.

As três cláusulas são opcionais. for ; i < 10; {} é válido, e o gofmt o reescreve como for i < 10 {}, que é a próxima forma.

Laço só com condição (o while do Go)

Só com uma condição, o for se comporta como o while de outras linguagens:

Não existe um do while separado. A página do laço while mostra como obter o comportamento de "executar pelo menos uma vez".

Laços infinitos

Um for sem nada depois dele repete para sempre. Saia com break, return, os.Exit ou um panic:

for {
	line, err := reader.ReadString('\n')
	if err != nil {
		break
	}
	process(line)
}

Esse é o formato padrão para servidores, workers e laços de entrada. Um for {} com corpo vazio queima um núcleo de CPU; em código real, o corpo bloqueia em alguma coisa (uma leitura, um recebimento de channel, um select).

Laços com range

range percorre uma coleção e entrega um ou dois valores por iteração. O que eles são depende do que você percorre:

PercorrendoPrimeiro valorSegundo valor
slice ou arrayíndiceelemento (uma cópia)
stringíndice em bytesrune (caractere Unicode)
mapchavevalor
channelelemento(nenhum)
inteiro n (Go 1.22)de 0 a n menos 1(nenhum)
função iteradora (Go 1.23)o que a função entregao que a função entrega

Três detalhes que a saída mostra:

  • A variável de valor é uma cópia. v *= 2 dentro do laço não mudaria o slice; para alterar elementos, acesse o slice pelo índice com nums[i], como faz o terceiro laço.
  • O índice de uma string é um offset em bytes. é ocupa dois bytes, então o índice pula de 1 para 3.
  • A ordem do map é aleatória de propósito. Go a embaralha para que o código não possa depender dela. slices.Sorted(maps.Keys(m)) (Go 1.23) entrega as chaves em ordem.

O range é explicado por completo, incluindo channels, funções iteradoras e as regras de cópia, na página de range.

break e continue

break encerra o laço mais interno. continue pula para a próxima iteração (executando o post antes, em um laço de três cláusulas):

break e continue com label

Um break simples só sai do laço mais interno. Para sair de um laço externo a partir de um laço aninhado, dê um label ao laço externo:

Um label é um identificador seguido de dois-pontos, colocado logo antes do for. Go trata um label sem uso como erro de compilação, igual a uma variável sem uso.

break dentro de switch e select

Dentro de um for, um break em um case de switch ou select sai do switch ou do select, não do laço:

for {
	switch cmd := next(); cmd {
	case "quit":
		break // only exits the switch; the loop keeps running
	}
}

Use um break com label, ou return, para sair do laço de dentro de um switch ou select.

Variáveis de laço desde o Go 1.22

O Go 1.22 mudou o escopo das variáveis de laço: agora cada iteração recebe uma cópia nova de i e v. Antes, uma única variável era reaproveitada no laço inteiro, o que quebrava closures e goroutines que a capturavam:

A partir do Go 1.22 isto imprime 0 1 2 e [aa bb cc]. Na semântica antiga, o mesmo programa escrito com for i := 0; i < 3; i++ (range sobre inteiro não existia antes do 1.22) imprimia 3 3 3, e as goroutines disputavam os i e name compartilhados. O antigo contorno, i := i no topo do corpo do laço, não é mais necessário.

O comportamento é escolhido por módulo, pela linha go do go.mod, e não pela versão do compilador. Um módulo que ainda diz go 1.21 mantém a semântica antiga mesmo quando compilado com o Go 1.24.

Erros comuns

Alterar a cópia. for _, v := range items { v.Count++ } altera uma cópia. Use items[i].Count++, ou percorra um slice de ponteiros.

Fazer append durante o range. O range avalia o slice uma vez, no início. Elementos acrescentados dentro do laço não são visitados, então o laço ainda termina, mas não vê os itens novos.

Remover de um slice pelo índice em um laço para a frente. Remover o elemento i desloca o resto para a esquerda, e o próximo elemento é pulado. Monte um slice novo, percorra de trás para a frente ou use slices.DeleteFunc.

Erro de um a mais com <=. for i := 0; i <= len(s); i++s[len(s)] na última passada e causa panic com index out of range. Use <, ou melhor, range.

Trabalho pesado na condição. A condição executa a cada iteração. for i := 0; i < expensiveCount(); i++ chama a função toda vez; calcule o valor uma vez antes do laço.

Usar um float como contador. for x := 0.0; x != 1.0; x += 0.1 nunca termina, porque 0.1 não tem representação binária exata. Conte com um inteiro e calcule o float a partir dele.

Perguntas frequentes

Como escrever um laço for em Go?

A forma clássica tem três partes separadas por ponto e vírgula e nenhum parêntese:

for i := 0; i < 5; i++ {
	fmt.Println(i)
}

Desde o Go 1.22 você também pode escrever for i := range 5, que conta de 0 a 4. Para percorrer um slice, use for i, v := range items.

Go tem laço while?

Não existe a palavra-chave while, mas um for só com condição é um laço while: for n > 0 { n /= 2 }. for { ... } sem condição é um laço infinito do qual você sai com break ou return.

Como percorrer um map em Go?

for key, value := range m { ... }. A ordem de iteração não é especificada, e o runtime a embaralha, então ela pode mudar de um laço para o outro. Nunca dependa dela. Para uma ordem estável, junte as chaves, ordene com slices.Sort e percorra as chaves ordenadas.

Como sair de um laço aninhado em Go?

Coloque um label antes do laço externo e cite-o no break: outer: for ... { for ... { if found { break outer } } }. Um break simples só sai do for, switch ou select mais interno. continue outer, da mesma forma, pula para a próxima iteração do laço com label.

O que mudou nas variáveis de laço no Go 1.22?

Antes do Go 1.22, um laço for tinha uma única variável compartilhada por todas as iterações, então closures e goroutines iniciadas no laço muitas vezes viam todas o valor final. Desde o Go 1.22 cada iteração ganha a sua própria cópia, então capturar i ou v em uma closure funciona como esperado. O novo comportamento vale quando o go.mod do módulo diz go 1.22 ou mais recente.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR