Médio Go

Envolvendo erros com %w e errors.Is

Enunciado

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.

Requisitos

  • Definir dois erros sentinela: ErrNomeVazio e ErrConfigInvalida.
  • A função LerConfig retorna ErrNomeVazio se nome == "".
  • A função LerConfig retorna ErrConfigInvalida se nome == "invalido", envolto com %w e contexto.
  • No main, usar errors.Is para detectar ErrConfigInvalida e imprimir "Configuração inválida detectada".
  • Imprimir também a mensagem completa do erro.

Código inicial

package main

import (
	"errors"
	"fmt"
)

var (
	ErrNomeVazio      = errors.New("nome vazio")
	ErrConfigInvalida = errors.New("configuração inválida")
)

func LerConfig(nome string) (string, error) {
	// Implemente
	return "", nil
}

func main() {
	// Chame LerConfig("invalido") e trate o erro
}

Saída esperada

Configuração inválida detectada
Erro completo: falha ao ler config: configuração inválida
Ver dica

Use fmt.Errorf("falha ao ler config: %w", ErrConfigInvalida) para envolver. No main, errors.Is encontrará o sentinela mesmo com o contexto extra.

Mostrar solução
package main

import (
	"errors"
	"fmt"
)

var (
	ErrNomeVazio      = errors.New("nome vazio")
	ErrConfigInvalida = errors.New("configuração inválida")
)

// LerConfig simula a leitura de uma configuração.
func LerConfig(nome string) (string, error) {
	if nome == "" {
		return "", ErrNomeVazio
	}
	if nome == "invalido" {
		// Envolve o erro sentinela com contexto usando %w
		return "", fmt.Errorf("falha ao ler config: %w", ErrConfigInvalida)
	}
	return "conteúdo de " + nome, nil
}

func main() {
	_, err := LerConfig("invalido")
	if err != nil {
		if errors.Is(err, ErrConfigInvalida) {
			fmt.Println("Configuração inválida detectada")
		}
		fmt.Printf("Erro completo: %v\n", err)
	}
}

Passo a passo

  1. Definimos dois erros sentinela: ErrNomeVazio e ErrConfigInvalida.
  2. Em LerConfig, se nome for vazio, retornamos ErrNomeVazio diretamente.
  3. Se nome for "invalido", usamos fmt.Errorf com %w para envolver ErrConfigInvalida e adicionar contexto ("falha ao ler config: ").
  4. No main, chamamos LerConfig("invalido") e obtemos o erro envolto.
  5. Usamos errors.Is(err, ErrConfigInvalida) para verificar se o erro original está na cadeia; como está, imprimimos a mensagem.
  6. Imprimimos o erro completo com %v, que mostra a mensagem contextualizada.

Por que funciona

%w faz com que o erro retornado por fmt.Errorf implemente o método Unwrap() error, permitindo que errors.Is percorra a cadeia até encontrar ErrConfigInvalida. Assim, mantemos o contexto sem perder a identidade do erro original.

Erros comuns

  • Usar %v em vez de %w: fmt.Errorf("falha: %v", ErrConfigInvalida) cria um novo erro sem envolver; errors.Is não encontrará o sentinela.
  • Comparar diretamente com ==: if err == ErrConfigInvalida falha porque o erro foi envolto.
  • Esquecer de importar errors: erro de compilação.

Outra forma de resolver

Se não precisar de contexto, pode retornar o sentinela diretamente. Mas o envolvimento é útil para rastrear a origem.

Saída esperada

Configuração inválida detectada
Erro completo: falha ao ler config: configuração inválida