Principais erros de desenvolvedores Go iniciantes: de A a Z

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Por que Go é simples, mas não fácil

\n\n

A linguagem Go (Golang) é frequentemente elogiada por sua simplicidade e concisão. No entanto, essa mesma simplicidade muitas vezes pega os iniciantes que vêm de linguagens mais "verbosas" como Python ou Java. Neste artigo, reunimos os principais erros de desenvolvedores Go iniciantes — desde problemas típicos com tratamento de erros até armadilhas não óbvias ao trabalhar com goroutines. Se você está apenas começando sua jornada no mundo Golang, esta seleção ajudará você a não cometer os mesmos erros que muitos antes de você.

\n\n

1. Ignorar erros e tratamento incorreto

\n\n

O erro mais comum em Go é ignorar os erros retornados. Ao contrário de exceções (exceptions) em Python ou Java, Go usa verificação explícita de erros através do valor retornado. Iniciantes frequentemente escrevem:

\n\n
package main\n\nimport (\n    "fmt"\n    "os"\n)\n\nfunc main() {\n    // ❌ ERRO: ignorando o erro\n    file, _ := os.Open("file.txt")\n    fmt.Println(file.Name())\n}\n
\n\n

Aqui, o símbolo _ (identificador vazio) literalmente diz ao compilador: "Não me importo com o erro". Em um projeto real, isso levará a pânico ou funcionamento incorreto. A abordagem correta é sempre verificar o erro:

\n\n
package main\n\nimport (\n    "fmt"\n    "os"\n)\n\nfunc main() {\n    file, err := os.Open("file.txt")\n    if err != nil {\n        // ✅ Tratando o erro\n        fmt.Println("Erro ao abrir arquivo:", err)\n        return\n    }\n    defer file.Close()\n    fmt.Println("Arquivo aberto com sucesso:", file.Name())\n}\n
\n\n

Dica: Nunca use _ para erros, a menos que tenha 100% de certeza de que o erro é impossível. É melhor escrever uma linha extra if err != nil do que procurar um bug à noite antes do prazo final.

\n\n

2. Problemas com goroutines: condição de corrida e vazamentos

\n\n

Go é famoso por sua simplicidade ao trabalhar com concorrência, mas isso também cria armadilhas. Iniciantes frequentemente esquecem da sincronização de acesso a dados compartilhados.

\n\n

2.1. Condição de corrida (Data Race)

\n\n

Imagine que várias goroutines escrevem simultaneamente na mesma variável:

\n\n
package main\n\nimport (\n    "fmt"\n    "sync"\n)\n\nfunc main() {\n    counter := 0\n    var wg sync.WaitGroup\n\n    for i := 0; i < 1000; i++ {\n        wg.Add(1)\n        go func() {\n            // ❌ ERRO: condição de corrida\n            counter++\n            wg.Done()\n        }()\n    }\n    wg.Wait()\n    fmt.Println("Counter:", counter) // Resultado imprevisível\n}\n
\n\n

O resultado será diferente a cada execução. Solução: usar mutex ou operações atômicas:

\n\n
package main\n\nimport (\n    "fmt"\n    "sync"\n    "sync/atomic"\n)\n\nfunc main() {\n    var counter int64\n    var wg sync.WaitGroup\n\n    for i := 0; i < 1000; i++ {\n        wg.Add(1)\n        go func() {\n            // ✅ Usando adição atômica\n            atomic.AddInt64(&counter, 1)\n            wg.Done()\n        }()\n    }\n    wg.Wait()\n    fmt.Println("Counter:", counter) // Sempre 1000\n}\n
\n\n

2.2. Vazamento de goroutines

\n\n

Outro erro clássico é iniciar uma goroutine e esquecê-la. Se a goroutine espera dados de um canal que nunca será fechado, ela ficará suspensa para sempre, consumindo memória:

\n\n
package main\n\nimport (\n    "fmt"\n    "time"\n)\n\nfunc worker(ch chan int) {\n    for msg := range ch {\n        fmt.Println(msg)\n    }\n}\n\nfunc main() {\n    ch := make(chan int)\n    go worker(ch) // ❌ ERRO: a goroutine nunca terminará\n    ch <- 1\n    ch <- 2\n    // Canal não fechado -> vazamento\n    time.Sleep(time.Second)\n}\n
\n\n

Solução: sempre feche o canal quando terminar de enviar dados, ou use contexto para cancelamento.

\n\n

3. Uso incorreto de slices e maps nil

\n\n

Em Go, n

Blogs

Book Recommendations