Switch em Go: sem fallthrough por padrão
1. A sintaxe básica do switch em Go
Em Go, a estrutura switch é uma das ferramentas mais elegantes para controle de fluxo condicional. Diferente de linguagens como C, C++ ou Java, o switch em Go não exige a declaração explícita de break após cada case. A execução não "cai" automaticamente para o próximo caso — a menos que você explicitamente queira isso.
package main
import "fmt"
func main() {
dia := 3
switch dia {
case 1:
fmt.Println("Segunda-feira")
case 2:
fmt.Println("Terça-feira")
case 3:
fmt.Println("Quarta-feira")
case 4:
fmt.Println("Quinta-feira")
case 5:
fmt.Println("Sexta-feira")
default:
fmt.Println("Fim de semana")
}
// Saída: Quarta-feira
}
Note que não há break entre os case. Em C, o mesmo código sem break imprimiria "Quarta-feira", "Quinta-feira", "Sexta-feira" e "Fim de semana" — um comportamento que frequentemente causa bugs. Go elimina esse problema por padrão.
2. Comportamento padrão: sem fallthrough
A decisão de design de não propagar execução entre case foi intencional. As vantagens são claras:
- Menos bugs: O erro clássico de esquecer um
breakem C/C++ simplesmente não existe em Go. - Código mais legível: Cada
caseé independente e auto-contido. - Refatoração segura: Reordenar ou adicionar
casenão quebra o fluxo.
func classificarNota(nota int) string {
switch {
case nota >= 90:
return "A"
case nota >= 80:
return "B"
case nota >= 70:
return "C"
case nota >= 60:
return "D"
default:
return "F"
}
}
Aqui, cada case é mutuamente exclusivo. Se a nota for 95, apenas o primeiro case executa — mesmo que os outros também sejam verdadeiros.
3. Fallthrough explícito com a palavra-chave fallthrough
Apesar do comportamento padrão ser sem propagação, Go oferece a palavra-chave fallthrough para forçar a execução do próximo case. Seu uso é explícito e intencional.
func main() {
i := 2
switch i {
case 1:
fmt.Println("Um")
fallthrough
case 2:
fmt.Println("Dois")
fallthrough
case 3:
fmt.Println("Três")
default:
fmt.Println("Outro")
}
// Saída:
// Dois
// Três
}
Limitações importantes do fallthrough:
- Só pode pular para o próximo case imediato, não para um case arbitrário.
- Não funciona no último case ou no default.
- A expressão do próximo case não é reavaliada — o fallthrough simplesmente executa o corpo do próximo caso.
Boas práticas: Use fallthrough raramente. Na maioria dos cenários, múltiplos valores em um único case são mais claros:
switch letra {
case 'a', 'e', 'i', 'o', 'u':
fmt.Println("Vogal")
default:
fmt.Println("Consoante")
}
4. Switch com inicialização inline (statement opcional)
Go permite incluir uma declaração de inicialização antes da expressão do switch, similar ao for:
func main() {
switch x := obterValor(); x {
case 10:
fmt.Println("Dez")
case 20:
fmt.Println("Vinte")
default:
fmt.Println("Outro valor:", x)
}
// x não existe aqui fora
}
A variável x tem escopo limitado ao bloco do switch. Isso é útil para:
- Manter o escopo restrito
- Evitar poluir o namespace da função
- Realizar cálculos ou chamadas de função uma única vez
switch n := rand.Intn(100); {
case n < 50:
fmt.Println("Menor que 50")
case n == 50:
fmt.Println("Exatamente 50")
default:
fmt.Println("Maior que 50")
}
5. Switch sem expressão (switch true)
Um padrão extremamente comum em Go é o switch sem expressão, que equivale a switch true. Cada case contém uma expressão booleana:
func main() {
idade := 25
switch {
case idade < 13:
fmt.Println("Criança")
case idade < 18:
fmt.Println("Adolescente")
case idade < 60:
fmt.Println("Adulto")
default:
fmt.Println("Idoso")
}
}
Este padrão substitui elegantemente longas cadeias de if-else if, tornando o código mais limpo e legível. Cada case é avaliado em ordem até encontrar o primeiro verdadeiro.
6. Switch com tipos (type switch)
Go possui um recurso poderoso para trabalhar com interfaces: o type switch. Ele permite verificar o tipo concreto de uma interface em tempo de execução:
func identificarTipo(v interface{}) string {
switch v.(type) {
case int:
return "Inteiro"
case string:
return "String"
case bool:
return "Booleano"
case []int:
return "Slice de inteiros"
default:
return "Tipo desconhecido"
}
}
func main() {
fmt.Println(identificarTipo(42)) // Inteiro
fmt.Println(identificarTipo("Go")) // String
fmt.Println(identificarTipo([]int{1,2,3})) // Slice de inteiros
}
Para acessar o valor tipado, use a sintaxe com variável:
switch v := valor.(type) {
case int:
fmt.Println("Inteiro:", v*2)
case string:
fmt.Println("String:", len(v))
}
7. Comparação com arrays, loops e controle de fluxo vizinhos
O switch em Go se alinha perfeitamente com a filosofia minimalista da linguagem. Enquanto Go tem apenas for para loops (sem while ou do-while), o switch substitui múltiplas construções condicionais.
Switch vs if-else:
// Com if-else
if x == 1 {
// ...
} else if x == 2 {
// ...
} else if x == 3 {
// ...
} else {
// ...
}
// Com switch - mais limpo
switch x {
case 1:
// ...
case 2:
// ...
case 3:
// ...
default:
// ...
}
Switch combinado com range e arrays:
notas := []int{85, 92, 67, 73, 88}
for _, nota := range notas {
switch {
case nota >= 90:
fmt.Printf("%d: A\n", nota)
case nota >= 80:
fmt.Printf("%d: B\n", nota)
default:
fmt.Printf("%d: C ou inferior\n", nota)
}
}
8. Erros comuns e boas práticas
Erro 1: Fallthrough acidental ou excessivo
// RUIM: fallthrough desnecessário
switch comando {
case "sair":
fmt.Println("Saindo...")
fallthrough // Por que? Isso não faz sentido!
case "help":
mostrarAjuda()
}
Erro 2: Esquecer que default não precisa ser o último
switch status {
case "ativo":
// ...
default:
fmt.Println("Status desconhecido")
case "inativo":
// ...
}
// Isso funciona, mas é confuso. Coloque default sempre no final.
Boas práticas:
- Cases alinhados: Mantenha os
casealinhados verticalmente para legibilidade. - Default sempre: Inclua um caso
defaultpara tratar valores inesperados. - Preferir múltiplos valores: Em vez de
fallthrough, usecase 1, 2, 3:. - Switch sem expressão para condições complexas: Use
switch { ... }em vez deif-else ifquando houver 3 ou mais condições. - Type switch com cuidado: Lembre-se que type switch só funciona com interfaces.
// Boa prática: múltiplos valores em um case
switch dia {
case "sábado", "domingo":
fmt.Println("Fim de semana")
default:
fmt.Println("Dia útil")
}
O switch em Go é uma ferramenta versátil que, quando usada corretamente, produz código limpo, seguro e expressivo. Sua simplicidade — sem fallthrough automático — é uma das muitas decisões de design que tornam Go uma linguagem pragmática e agradável de usar.
Referências
- A Tour of Go: Switch — Documentação oficial interativa explicando a sintaxe básica do switch em Go.
- Effective Go: Switch — Guia oficial com boas práticas e padrões de uso do switch.
- Go by Example: Switch — Exemplos práticos e comentados de diferentes formas de usar switch em Go.
- The Go Programming Language Specification: Switch statements — Especificação técnica completa do switch na linguagem Go.
- YourBasic Go: Switch statement — Tutorial detalhado com exemplos avançados, incluindo type switch e fallthrough.
- DigitalOcean: How To Write Switch Statements in Go — Tutorial prático cobrindo desde o básico até casos de uso avançados.
- GolangBot: Switch Statement in Go — Guia completo com exemplos de código e explicações sobre fallthrough e type switch.