Introdução: Por que Go parece simples, mas esconde armadilhas
Go (Golang) é uma linguagem compilada, estaticamente tipada, criada nos laboratórios do Google. É frequentemente elogiada por sua simplicidade de sintaxe, suporte embutido para concorrência e alta performance. No entanto, essa aparente simplicidade muitas vezes prega uma peça em iniciantes vindos de linguagens dinâmicas (Python, JavaScript) ou até mesmo de C++.
Muitos desenvolvedores, ao começarem a escrever em Go, cometem os mesmos erros típicos. Neste artigo, vamos analisar o top 5 dos problemas mais comuns enfrentados por desenvolvedores Go iniciantes e mostrar como corrigi-los com exemplos de código claros.
1. Ignorar erros retornados (Error Handling)
Problema
Em Go, não existem exceções (try-catch). Um erro é simplesmente um valor que a função retorna como último argumento. O erro mais comum de um iniciante é atribuir o resultado a uma variável, mas ignorar o erro usando o sublinhado _.
// RUIM: erro engolidoresult, _ := doSomething()fmt.Println(result)Por que isso é ruim?
O programa continuará executando com dados incorretos, o que pode levar a pânicos, vazamentos de memória ou bugs lógicos difíceis de detectar.
Como fazer corretamente
Sempre verifique o erro. Use o padrão idiomático:
// BOM: erro tratadoresult, err := doSomething()if err != nil { log.Printf("Erro ao executar doSomething: %v", err) return // ou panic, ou outra lógica}fmt.Println(result)Dica: Escreva seu código de forma que if err != nil se torne um reflexo seu. Não tenha medo do retorno antecipado (early return) — isso torna o código mais limpo.
2. Confusão entre nil e slices/maps vazios
Problema
Em Go, nil não é um "objeto vazio". É o valor zero para ponteiros, slices, maps, canais e interfaces. Iniciantes frequentemente tentam escrever dados em um map ou slice nil, resultando em pânico.
// RUIM: pânico ao escrever em map nilvar m map[string]intm["key"] = 42 // panic: assignment to entry in nil mapComo fazer corretamente
Sempre inicialize maps e slices antes de usar:
// BOM: inicialização com makem := make(map[string]int)m["key"] = 42
// Ou com literalm2 := map[string]int{}m2["key"] = 42Com slices, a situação é mais sutil: você pode ler um slice nil (ele retorna um slice vazio), mas não pode escrever por índice. Use append:
var s []ints = append(s, 1) // OK, cria um novo slice// s[0] = 1 // panic: runtime error: index out of range [0] with length 03. Uso incorreto de goroutines e condição de corrida (Data Race)
Problema
Goroutines são threads leves. Iniciantes frequentemente iniciam goroutines esquecendo de sincronizar o acesso a dados compartilhados. Isso leva a uma condição de corrida (data race) — comportamento indefinido do programa.
// RUIM: condição de corridavar counter intfor i := 0; i < 1000; i++ { go func() { counter++ // inseguro! }()}time.Sleep(time.Second)fmt.Println(counter) // resultado imprevisívelComo fazer corretamente
Use mutexes (sync.Mutex) ou canais para sincronização:
// BOM: uso de mutexvar ( counter int mu sync.Mutex)for i := 0; i < 1000; i++ { go func() { mu.Lock() counter++ mu.Unlock() }()}// Aguarda a conclusão (melhor usar sync.WaitGroup)time.Sleep(time.Second)fmt.Println(counter) // 1000Importante: Sempre verifique seu código para condições de corrida usando a flag -race: go run -race main.go.