Por que Go parece simples, mas quebra os iniciantes?
\n\nGo (ou Golang) é uma linguagem que foi criada com um único objetivo: fazer com que programadores sofram menos. Sintaxe minimalista, concorrência embutida, compilação rápida — parece que dá para aprender em uma semana. E sim, dá para aprender. Mas "escrever código bom" e "escrever código em Go" são duas histórias diferentes.
\n\nIniciantes frequentemente trazem hábitos do Python, JavaScript ou Java e tentam encaixá-los em Go. O resultado são bugs difíceis de detectar, pânico em tempo de execução e a sensação de que "Go está quebrado de alguma forma". Spoiler: Go não está quebrado. Ele apenas pensa de forma diferente.
\n\nNeste artigo, vamos analisar os 5 erros mais comuns ao aprender Go. Se você está começando — leia com atenção. Se você já programa em Go — verifique se ainda não os comete.
\n\nErro nº1: Ignorar erros (e o hábito do Python)
\n\nEm Python ou JavaScript, você está acostumado que uma função pode retornar um resultado ou lançar uma exceção. Você envolve a chamada em try/catch e vive tranquilo. Em Go é diferente: não existem exceções. Existem apenas valores de retorno, e um deles é o erro.
\n\nO erro mais popular de iniciantes é escrever result, _ := someFunc() e esquecer do erro. Ou, pior ainda, simplesmente não verificá-lo:
// RUIM: erro ignorado\nfile, _ := os.Open("config.yaml")\n// Se o arquivo não existir — file == nil, e a próxima linha causará pânico\ndefer file.Close()\n\n\nEm Go, o erro não é algo assustador. É apenas um valor. Ele precisa ser verificado. Sempre. Sem exceções.
\n\nComo fazer corretamente?
\n\n// BOM: verificamos o erro imediatamente\nfile, err := os.Open("config.yaml")\nif err != nil {\n log.Fatalf("não foi possível abrir o arquivo: %v", err)\n}\ndefer file.Close()\n\n\nIsso não é paranoia. É disciplina. Go ensina você a ser cuidadoso. Se você ignorar um erro em produção — prepare-se para que às 3 da manhã o serviço caia e os logs fiquem em silêncio.
\n\nDica: nunca use _ para o erro, a menos que tenha 100% de certeza de que ele nunca ocorrerá. E essas situações no código real quase não existem.
Erro nº2: Pânico onde é necessário um erro
\n\nEm Go, existe o mecanismo panic e recover. Iniciantes frequentemente os confundem com exceções e começam a lançar pânico a qualquer problema. Isso é um erro.
panic é uma parada de emergência do programa. Ele é destinado a situações em que a continuação da execução é impossível: por exemplo, desreferenciar um ponteiro nulo ou acessar um índice fora dos limites de um array. Usar panic para tratar lógica de negócios é falta de educação.
// RUIM: pânico em vez de erro\nfunc divide(a, b int) int {\n if b == 0 {\n panic("divisão por zero!")\n }\n return a / b\n}\n\n\nA abordagem correta é retornar um erro:
\n\n// BOM: retornamos um erro\nfunc divide(a, b int) (int, error) {\n if b == 0 {\n return 0, fmt.Errorf("divisão por zero")\n }\n return a / b, nil\n}\n\n\nUse panic apenas para situações verdadeiramente críticas. Todo o resto são erros. Go fornece error não por acaso.
Erro nº3: Trabalho incorreto com goroutines e falta de sincronização
\n\nGoroutines são, talvez, a funcionalidade mais legal do Go. Mas também é a mais perigosa para iniciantes. Cenário típico: você inicia 1000 goroutines, escreve em uma variável compartilhada — e obtém uma condição de corrida (data race).
\n\n// RUIM: condição de corrida\nvar counter int\nfor i := 0; i < 1000; i++ {\n go func() {\n counter++ // inseguro!\n }()\n}\ntime.Sleep(time.Second)\nfmt.Println(counter) // resultado imprevisível\n\n\nPor que isso é um problema? Porque counter++ não é uma operação atômica. Ela consiste em leitura, incremento e escrita. Duas goroutines podem ler o mesmo valor, incrementá