Menu
Coddy logo textTech

Unwrapping com `errors.Is`

Parte da seção Lógica & Fluxo do Journey de GO da Coddy. Lição 40 de 68.

Ao trabalhar com erros encapsulados, você precisa de uma maneira de verificar se um erro específico existe em qualquer lugar na cadeia de erros. A função errors.Is fornece exatamente essa capacidade, permitindo identificar erros sentinela mesmo quando eles foram encapsulados várias vezes.

A função errors.Is recebe dois parâmetros: o erro que você deseja examinar e o erro alvo que você está procurando. Ela retorna true se o erro alvo for encontrado em qualquer lugar na cadeia de erros:

var ErrNotFound = errors.New("not found")

wrappedErr := fmt.Errorf("failed to load user: %w", ErrNotFound)

if errors.Is(wrappedErr, ErrNotFound) {
    fmt.Println("This is a not found error")
}

Esta é a maneira moderna e recomendada de verificar erros específicos em Go. Ao contrário da comparação de strings ou verificações de igualdade direta, errors.Is funciona corretamente com erros encapsulados e segue a cadeia de erros para encontrar correspondências. Isso torna o seu tratamento de erros robusto e confiável, mesmo quando os erros passam por várias camadas da sua aplicação.

challenge icon

Desafio

Fácil

Crie um sistema de monitoramento de conexão com banco de dados que use errors.Is para identificar erros de conexão específicos em cadeias de erros encapsulados. Este desafio demonstra como usar errors.Is para detectar erros sentinela mesmo quando eles foram encapsulados com contexto adicional por meio de várias camadas da aplicação.

Você receberá duas entradas:

  • Uma string contendo detalhes da operação do banco de dados no formato "database_name,operation,error_type" (por exemplo, "users_db,connect,connection_timeout")
  • Uma string contendo o contexto da aplicação no formato "service_name,retry_count" (por exemplo, "AuthService,3")

Sua tarefa é:

  1. Definir três erros sentinela usando errors.New():
    • ErrConnectionTimeout com a mensagem "connection timeout"
    • ErrConnectionRefused com a mensagem "connection refused"
    • ErrDatabaseNotFound com a mensagem "database not found"
  2. Analisar a primeira entrada dividindo-a nas vírgulas para obter o nome do banco de dados, a operação e o tipo de erro
  3. Analisar a segunda entrada dividindo-a nas vírgulas para obter o nome do serviço e a quantidade de tentativas
  4. Criar o erro original com base no tipo de erro:
    • Se o tipo de erro for "connection_timeout": usar ErrConnectionTimeout
    • Se o tipo de erro for "connection_refused": usar ErrConnectionRefused
    • Se o tipo de erro for "database_not_found": usar ErrDatabaseNotFound
    • Para qualquer outro tipo de erro: usar errors.New("unknown database error")
  5. Criar um erro encapsulado no nível do banco de dados usando fmt.Errorf com %w: "failed to [operation] database [database_name]: %w"
  6. Criar um erro encapsulado no nível do serviço: "[service_name] database operation failed after [retry_count] retries: %w"
  7. Usar errors.Is para verificar se o erro final encapsulado corresponde a cada erro sentinela e exibir os resultados:
    • "Checking for connection timeout: [true/false]"
    • "Checking for connection refused: [true/false]"
    • "Checking for database not found: [true/false]"
  8. Exibir a cadeia de erros:
    • "Error Chain:"
    • "Original: [original_error_message]"
    • "Database level: [database_level_error_message]"
    • "Service level: [service_level_error_message]"
  9. Exibir a análise do erro:
    • "Error Analysis:"
    • "Database: [database_name]"
    • "Operation: [operation]"
    • "Service: [service_name]"
    • "Retries: [retry_count]"
    • "Error type detected: [detected_error_type]", em que detected_error_type é um de "Connection Timeout", "Connection Refused", "Database Not Found" ou "Unknown Error"

Use o pacote strings para dividir as strings de entrada nas vírgulas, o pacote errors para os erros sentinela e errors.Is, e o pacote fmt para encapsulamento de erros. Este desafio demonstra como errors.Is fornece uma identificação robusta de erros que funciona corretamente com erros encapsulados, tornando-a essencial para um tratamento de erros confiável em aplicações complexas.

Experimente você mesmo

package main

import (
	"errors"
	"fmt"
	"strings"
)

func main() {
	// Lê a entrada
	var dbOperation string
	var appContext string
	fmt.Scanln(&dbOperation)
	fmt.Scanln(&appContext)
	
	// Faz o parsing das entradas
	dbParts := strings.Split(dbOperation, ",")
	databaseName := dbParts[0]
	operation := dbParts[1]
	errorType := dbParts[2]
	
	contextParts := strings.Split(appContext, ",")
	serviceName := contextParts[0]
	retryCount := contextParts[1]
	
	// TODO: Escreva seu código abaixo
	// 1. Defina os três erros sentinela usando errors.New()
	// 2. Crie o erro original baseado no tipo de erro
	// 3. Crie o erro encapsulado (wrapped) de nível de banco de dados usando fmt.Errorf com %w
	// 4. Crie o erro encapsulado de nível de serviço
	// 5. Use errors.Is para verificar cada erro sentinela
	// 6. Exiba os resultados e a cadeia de erros
	
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Lógica & Fluxo

Pratique por conta própria: Compilador de Go online