Error Handling: erros são valores, não exceções
Em Go, erros são apenas valores que você retorna e checa. Sem try/catch.
go
import (
"errors"
"fmt"
"os"
)
func lerArquivo(caminho string) ([]byte, error) {
dados, err := os.ReadFile(caminho)
if err != nil {
// Envolva o erro com contexto para facilitar debug
return nil, fmt.Errorf("falha ao ler %s: %w", caminho, err)
}
return dados, nil
}
func main() {
dados, err := lerArquivo("config.json")
if err != nil {
// Verificar tipo de erro
if errors.Is(err, os.ErrNotExist) {
fmt.Println("Arquivo não encontrado, criando padrão...")
return
}
fmt.Println("Erro inesperado:", err)
return
}
fmt.Println("Conteúdo:", string(dados))
}Erros customizados
go
// Definindo um tipo de erro com contexto rico
type ErroValidacao struct {
Campo string
Motivo string
}
// Para satisfazer a interface "error", precisa do método Error()
func (e *ErroValidacao) Error() string {
return fmt.Sprintf("validação falhou no campo %s: %s", e.Campo, e.Motivo)
}
func validarEmail(email string) error {
if email == "" {
return &ErroValidacao{Campo: "email", Motivo: "vazio"}
}
return nil
}Padrão idiomático: if err != nil
Sim, você vai escrever isso toneladas de vezes. Não é feio, é explícito:
go
// O famoso "happy path" colado à esquerda
func process(dado string) error {
parsed, err := parse(dado)
if err != nil {
return fmt.Errorf("parse: %w", err)
}
validated, err := validar(parsed)
if err != nil {
return fmt.Errorf("validar: %w", err)
}
if err := salvar(validated); err != nil {
return fmt.Errorf("salvar: %w", err)
}
return nil
}Defer: garantindo limpeza
defer adia a execução de uma função até o final da função atual. Perfeito para fechar recursos:
go
func copiarArquivo(origem, destino string) error {
src, err := os.Open(origem)
if err != nil {
return err
}
defer src.Close() // será chamado quando a função retornar
dst, err := os.Create(destino)
if err != nil {
return err
}
defer dst.Close() // mesma coisa
_, err = io.Copy(dst, src)
return err
}Você nunca esquece de fechar arquivos, conexões de banco, mutexes. O
defer roda mesmo se a função entrar em pânico (panic).Organização de código
Estrutura de pastas típica de um projeto backend
meu-projeto/
├── go.mod # define o módulo e dependências
├── go.sum # hashes de verificação
├── cmd/
│ └── api/
│ └── main.go # ponto de entrada
├── internal/ # código privado do projeto
│ ├── handler/ # camada HTTP
│ ├── service/ # regras de negócio
│ ├── repository/ # acesso a dados
│ └── model/ # structs de domínio
├── pkg/ # código reutilizável (público)
└── configs/
└── config.yaml
A pasta
internal/ é especial — só código DENTRO do seu projeto pode importar dela. O Go bloqueia importações externas. Use isso para esconder detalhes.Convenções de nomes
| O quê | Convenção | Exemplo |
|---|---|---|
| Pacote | minúsculo, curto, sem underscores | httputil, jwt |
| Função/variável exportada (pública) | PascalCase (começa maiúscula) | BuscarUsuario |
| Função/variável interna (privada) | camelCase (começa minúscula) | validarEmail |
| Interface | normalmente termina em -er | Reader, Writer, Notifier |
| Constantes | PascalCase ou SCREAMING | MaxConexoes, DEFAULT_PORT |
Visibilidade em Go: é só pela primeira letra. Maiúscula = pública. Minúscula = privada (do pacote). Não tem
public/private. Genial.Padrões comuns idiomáticos
Construtor: função New...
Go não tem construtores, mas a convenção é uma função New<Tipo>:
go
type Server struct {
port int
db *DB
}
func NewServer(port int, db *DB) *Server {
return &Server{
port: port,
db: db,
}
}
// Uso
srv := NewServer(8080, myDB)Receiver pequeno e consistente
Use a primeira letra do tipo como nome do receiver — sempre o mesmo dentro de um arquivo:
go
// ✅ Bom
func (u *User) Salvar() error { ... }
func (u *User) Validar() error { ... }
// ❌ Ruim — inconsistente
func (user *User) Salvar() error { ... }
func (this *User) Validar() error { ... }Aceite interfaces, retorne structs
go
// ✅ Aceita qualquer coisa que satisfaça io.Reader
func process(r io.Reader) (*Result, error)
// ❌ Restringe demais — só aceita esse tipo específico
func process(r *bytes.Buffer) (*Result, error)