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.
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Desafio
FácilConstrua um sistema de monitoramento de conexão de banco de dados que utiliza errors.Is para identificar erros de conexão específicos em cadeias de erros envolvidos (wrapped). Este desafio demonstra como usar errors.Is para detectar erros sentinela mesmo quando eles foram envolvidos com contexto adicional através de múltiplas 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"(ex:"users_db,connect,connection_timeout") - Uma string contendo o contexto da aplicação no formato
"service_name,retry_count"(ex:"AuthService,3")
Sua tarefa é:
- Definir três erros sentinela usando
errors.New():ErrConnectionTimeoutcom a mensagem"connection timeout"ErrConnectionRefusedcom a mensagem"connection refused"ErrDatabaseNotFoundcom a mensagem"database not found"
- Analisar a primeira entrada dividindo-a por vírgulas para obter o nome do banco de dados, a operação e o tipo de erro
- Analisar a segunda entrada dividindo-a por vírgulas para obter o nome do serviço e a contagem de tentativas
- Criar o erro original baseado no tipo de erro:
- Se o tipo de erro for
"connection_timeout": useErrConnectionTimeout - Se o tipo de erro for
"connection_refused": useErrConnectionRefused - Se o tipo de erro for
"database_not_found": useErrDatabaseNotFound - Para qualquer outro tipo de erro: use
errors.New("unknown database error")
- Se o tipo de erro for
- Criar um erro envolvido em nível de banco de dados usando
fmt.Errorfcom%w:"failed to [operation] database [database_name]: %w" - Criar um erro envolvido em nível de serviço:
"[service_name] database operation failed after [retry_count] retries: %w" - Usar
errors.Ispara verificar se o erro envolvido final 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]"
- Exibir a cadeia de erros:
"Error Chain:""Original: [original_error_message]""Database level: [database_level_error_message]""Service level: [service_level_error_message]"
- 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]"onde detected_error_type é um dos seguintes: "Connection Timeout", "Connection Refused", "Database Not Found", ou "Unknown Error"
Use o pacote strings para dividir as strings de entrada por vírgulas, o pacote errors para os erros sentinela e errors.Is, e o pacote fmt para o envolvimento de erros. Este desafio demonstra como o errors.Is fornece uma identificação de erro robusta que funciona corretamente com erros envolvidos, tornando-o essencial para o tratamento confiável de erros em aplicações complexas.
Folha de consulta
A função errors.Is verifica se um erro específico existe em qualquer lugar de uma cadeia de erros, mesmo quando encapsulado (wrapped) várias vezes:
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")
}errors.Is recebe dois parâmetros: o erro a ser examinado e o erro alvo a ser encontrado. Ela retorna true se o erro alvo for encontrado em qualquer lugar da cadeia de erros.
Esta é a maneira moderna e recomendada de verificar erros específicos em Go, pois funciona corretamente com erros encapsulados, ao contrário da comparação de strings ou verificações de igualdade direta.
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
}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
1Fluxo de Controle Avançado
Switch com `fallthrough`Interrompendo Loops AninhadosContinuando um Loop EspecíficoA Instrução `goto`Recapitulação - Controle de Loop Avançado4Projeto: Lista de Tarefas Simples
Configuração do ProjetoAdicionando uma Tarefa7Tratamento de Erros em Profundidade
Tipos de Erro PersonalizadosWrapping de Erros com `%w`Unwrapping com `errors.Is`Unwrapping com `errors.As`Entendendo o `panic`Usando o `recover`Recapitulação - Divisão Segura2Structs e Métodos
Definindo Métodos em StructsRecebedores de ValorRecebedores de PonteiroEscolhendo RecebedoresMétodos vs FunçõesRecapitulação - Comportamento de Structs5Mapas em Profundidade
Mapas de StructsPonteiros como Valores de MapVerificando Mapas NilComparando MapasRecapitulação - Contador de Frequência de Palavras3Interfaces (O Básico)
O que é uma Interface?Definindo uma InterfaceImplementando uma InterfaceUsando Tipos de InterfaceInterface VaziaAsserções de TipoType SwitchRecapitulação - Formas e Comportamentos