Go Erros Intermediário
Tratamento de erros
Em Go, erros são valores comuns, não exceções. O tipo error é uma interface que declara apenas o método Error() string. Isso significa que funções retornam erros como qualquer outro valor, geralmente como último retorno. O chamador decide o que fazer: tratar, ignorar ou propagar. Essa abordagem torna o fluxo de erro explícito e fácil de rastrear.
Para criar erros, use errors.New ou fmt.Errorf. Desde Go 1.13, fmt.Errorf suporta o verbo %w para encadear erros (wrapping). O erro resultante envolve o original, permitindo inspecioná-lo depois. A função errors.Is verifica se um erro (ou qualquer erro na cadeia) é igual a um valor sentinela. Já errors.As verifica se algum erro na cadeia é de um tipo específico e, se for, atribui-o a uma variável.
Essas ferramentas permitem que camadas superiores tomem decisões baseadas na causa raiz sem quebrar o encapsulamento. Por exemplo, um erro de banco de dados pode ser envolvido com contexto adicional, mas ainda assim ser identificado como sql.ErrNoRows.
Neste card, vamos explorar como criar, envolver e inspecionar erros usando %w, errors.Is e errors.As.
Pontos-chave
erroré uma interface com o métodoError() string; erros são valores comuns.fmt.Errorfcom%wenvolve um erro, preservando a cadeia para inspeção.errors.Iscompara um erro com um valor sentinela em toda a cadeia.errors.Asextrai um erro de um tipo específico da cadeia, atribuindo-o a uma variável.- Sempre trate erros explicitamente; não ignore retornos de erro.
package main
import (
"errors"
"fmt"
)
// ErrNotFound é um erro sentinela para recursos não encontrados.
var ErrNotFound = errors.New("recurso não encontrado")
// ValidationError representa um erro de validação com detalhes.
type ValidationError struct {
Field string
Msg string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validação falhou no campo %s: %s", e.Field, e.Msg)
}
// BuscarUsuario simula a busca de um usuário e retorna erros variados.
func BuscarUsuario(id int) (string, error) {
if id <= 0 {
return "", &ValidationError{Field: "id", Msg: "deve ser positivo"}
}
if id == 42 {
return "", fmt.Errorf("usuário %d: %w", id, ErrNotFound)
}
return fmt.Sprintf("Usuário%d", id), nil
}
func main() {
// Teste 1: validação
_, err := BuscarUsuario(-1)
if err != nil {
var valErr *ValidationError
if errors.As(err, &valErr) {
fmt.Printf("Erro de validação: %v\n", valErr)
}
}
// Teste 2: não encontrado
_, err = BuscarUsuario(42)
if err != nil {
if errors.Is(err, ErrNotFound) {
fmt.Println("Usuário não encontrado (via errors.Is)")
}
fmt.Printf("Erro original: %v\n", err)
}
}