Principais erros de desenvolvedores Go iniciantes: como evitá-los
Go (ou Golang) é uma linguagem de programação compilada e estaticamente tipada, criada nos laboratórios do Google. Ela ganhou popularidade devido à sua simplicidade, desempenho e suporte embutido para concorrência. No entanto, mesmo com uma sintaxe tão concisa, os iniciantes frequentemente cometem os mesmos erros. Neste artigo, analisaremos os 4 principais erros típicos de desenvolvedores Go iniciantes e mostraremos como evitá-los.
1. Ignorar erros retornados
Um dos erros mais comuns é ignorar os erros retornados por funções. Em Go, não há exceções (try-catch), e os erros são valores comuns que precisam ser tratados explicitamente. Muitos iniciantes, acostumados com outras linguagens, simplesmente atribuem o resultado a uma variável, esquecendo de verificar o err.
Incorreto:
package main
import ( "fmt" "os")
func main() { file, _ := os.Open("config.txt") // Ignorando o erro fmt.Println(file.Name())}Se o arquivo não existir, o programa entrará em pânico (causará um panic) ou funcionará com um ponteiro nil, o que levará a um comportamento inesperado.
Correto:
package main
import ( "fmt" "log" "os")
func main() { file, err := os.Open("config.txt") if err != nil { log.Fatalf("Não foi possível abrir o arquivo: %v", err) } defer file.Close() fmt.Println(file.Name())}Dica: Sempre verifique o err imediatamente após a chamada da função. Use log.Fatal ou retorne o erro para cima na pilha, mas nunca o ignore.
2. Trabalho incorreto com goroutines e condições de corrida
Goroutines são threads leves em Go. No entanto, iniciantes frequentemente iniciam goroutines sem se preocupar com a sincronização do acesso a dados compartilhados. Isso leva a condições de corrida (data race), onde múltiplas goroutines leem e escrevem em uma mesma variável simultaneamente.
Incorreto:
package main
import ( "fmt" "sync")
func main() { counter := 0 var wg sync.WaitGroup
for i := 0; i < 1000; i++ { wg.Add(1) go func() { defer wg.Done() counter++ // Condição de corrida! }() } wg.Wait() fmt.Println(counter) // O resultado pode ser qualquer um (não 1000)}Correto (usando mutex):
package main
import ( "fmt" "sync")
type Counter struct { mu sync.Mutex value int}
func (c *Counter) Increment() { c.mu.Lock() defer c.mu.Unlock() c.value++}
func (c *Counter) Value() int { c.mu.Lock() defer c.mu.Unlock() return c.value}
func main() { counter := &Counter{} var wg sync.WaitGroup
for i := 0; i < 1000; i++ { wg.Add(1) go func() { defer wg.Done() counter.Increment() }() } wg.Wait() fmt.Println(counter.Value()) // Sempre 1000}Dica: Use mutexes (sync.Mutex) ou channels para sincronização. Execute testes com a flag -race: go test -race.
3. Confusão entre slice nil e slice vazio
Em Go, slices podem ser nil ou vazios. Iniciantes frequentemente não entendem a diferença, o que leva a erros na serialização (JSON) ou ao passar slices para funções.
- Slice nil: declarado como
var s []int. Ele não possui um array subjacente. - Slice vazio: criado como
s := []int{}oumake([]int, 0). Ele possui um array subjacente, mas o comprimento é 0.
Exemplo de confusão:
package main
import ( "e