Principais erros de desenvolvedores Go iniciantes: de A a Z
Go (Golang) é uma linguagem de programação moderna, rápida e fácil de aprender, criada nos laboratórios do Google. No entanto, sua sintaxe concisa e características de gerenciamento de memória frequentemente se tornam obstáculos para iniciantes. Neste artigo, analisaremos os erros mais comuns de desenvolvedores Go iniciantes — desde trabalhar com nil até o tratamento incorreto de goroutines. Você aprenderá como evitá-los e escrever um código mais limpo e confiável.
1. Ignorar o tratamento de erros e pânico com nil
Em Go, erros são valores. Um dos principais erros de iniciantes é ignorar o erro retornado usando sublinhado (_) ou simplesmente não verificar nil.
Exemplo de código ruim:
package main
import (\t"fmt"\t"os")
func main() {\tfile, _ := os.Open("config.json") // Ignoramos o erro\tfmt.Println(file.Name())}Se o arquivo não existir, o programa entrará em pânico ou exibirá uma string vazia. A abordagem correta é sempre verificar o erro.
Como deveria ser:
package main
import (\t"fmt"\t"os")
func main() {\tfile, err := os.Open("config.json")\tif err != nil {\t\tfmt.Println("Erro ao abrir arquivo:", err)\t\treturn\t}\tdefer file.Close()\tfmt.Println(file.Name())}Particularmente perigoso é o erro de desreferenciar um ponteiro que é igual a nil. Isso causa pânico (panic). Sempre verifique ponteiros e interfaces para nil antes de chamar seus métodos.
2. Falta de compreensão sobre goroutines e sincronização
Goroutines são threads leves. Iniciantes frequentemente iniciam goroutines esquecendo de sincronizar o acesso a dados compartilhados. Isso leva a condições de corrida (data race).
Erro típico:
package main
import (\t"fmt"\t"time")
func main() {\tcount := 0\tfor i := 0; i < 1000; i++ {\t\tgo func() {\t\t\tcount++ // Condição de corrida!\t\t}()\t}\ttime.Sleep(1 * time.Second)\tfmt.Println(count) // Resultado imprevisível}Use channels ou mutexes (sync.Mutex) para sincronização. Channels são a forma idiomática de comunicação entre goroutines em Go.
Correção usando channel:
package main
import (\t"fmt")
func main() {\tch := make(chan int)\tgo func() {\t\tch <- 42\t}()\tvalue := <-ch\tfmt.Println(value)}Para sincronização complexa, use o pacote sync. E nunca use time.Sleep para sincronização — isso não é confiável.
3. Trabalho incorreto com interfaces e interface vazia
Interfaces em Go são contratos. O erro de iniciantes é pensar que qualquer tipo pode ser simplesmente passado para uma função que espera uma interface específica. Também é comum abusar da interface vazia interface{} (em Go 1.18+ é any).
Problema: passar um valor por valor para uma função que espera uma interface implementada por um ponteiro.
type Stringer interface {\tString() string}
type MyType struct {\tValue int}
// Implementação para ponteirofunc (m *MyType) String() string {\treturn fmt.Sprintf("%d", m.Value)}
func Print(s Stringer) {\tfmt.Println(s.String())}
func main() {\tobj := MyType{Value: 10}\t// Print(obj) // Erro de compilação! *MyType, não MyType\tPrint(&obj) // Funciona}A interface vazia é boa para funções como fmt.Println, mas não para seu código. Ela apaga informações de tipo e requer conversões, o que pode causar pânico. Use genéricos (Go 1.18+) ou interfaces específicas.
Dica: Se você precisa trabalhar com diferentes tipos, defina uma interface com os métodos necessários, em vez de usar any.