Da trilha de Go Este conceito ainda não saiu como card do dia. ir para o card de hoje

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étodo Error() string; erros são valores comuns.
  • fmt.Errorf com %w envolve um erro, preservando a cadeia para inspeção.
  • errors.Is compara um erro com um valor sentinela em toda a cadeia.
  • errors.As extrai 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.
error_handling.go
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)
	}
}

Exercícios

  1. 1
    Fácil

    Erro sentinela e errors.Is

    Crie uma função Dividir(a, b float64) (float64, error) que retorna um erro sentinela ErrDivisaoPorZero quando b for zero. No main, chame a função com b=0 e use errors.Is para verificar se o erro é ErrDivisaoPorZero, imprimindo uma mensagem adequada.

    Resolver
  2. 2
    Médio

    Envolvendo erros com %w e errors.Is

    Crie uma função LerConfig(nome string) (string, error) que simula a leitura de um arquivo de configuração. Se nome for vazio, retorne um erro sentinela ErrNomeVazio. Se nome for "invalido", retorne um erro personalizado ErrConfigInvalida (também sentinela). Caso contrário, retorne "conteúdo de " + nome. No main, chame a função com "invalido" e use errors.Is para verificar se o erro é ErrConfigInvalida, imprimindo uma mensagem. Envolva o erro com contexto usando fmt.Errorf com %w.

    Resolver
  3. 3
    Desafio

    Erros personalizados com errors.As

    Implemente um tipo de erro personalizado ErroValidacao com campos Campo e Mensagem. Crie uma função ValidarUsuario(nome string, idade int) error que retorna um *ErroValidacao se nome estiver vazio ou idade for menor que 18. A função deve retornar o primeiro erro encontrado. No main, chame ValidarUsuario("", 20) e use errors.As para extrair o *ErroValidacao e imprimir "Erro no campo: nome - mensagem: nome não pode ser vazio". Depois, chame ValidarUsuario("João", 15) e faça o mesmo para o campo idade.

    Resolver

Continue estudando