Encapsulamento de Erros (fmt.Errorf)
Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy. Lição 54 de 107.
Quando os erros passam por várias camadas da sua aplicação, saber onde um erro se originou torna-se crucial. A função fmt.Errorf do Go com o verbo %w permite encapsular erros, preservando o erro original enquanto adiciona contexto.
O encapsulamento de erros cria uma cadeia de erros. Cada camada pode adicionar informações sobre o que estava tentando fazer quando o erro ocorreu:
func ReadConfig(filename string) error {
data, err := os.ReadFile(filename)
if err != nil {
return fmt.Errorf("reading config file: %w", err)
}
// processar dados...
return nil
}O verbo %w é especial. Ele envolve o erro original dentro do novo erro. Isso é diferente de %v, que apenas converte o erro em uma string e perde a identidade do erro original.
func LoadSettings() error {
err := ReadConfig("settings.json")
if err != nil {
return fmt.Errorf("loading settings: %w", err)
}
return nil
}Quando LoadSettings falha, a mensagem de erro mostra a cadeia completa: "loading settings: reading config file: open settings.json: no such file or directory". Cada camada adiciona contexto, tornando a depuração muito mais fácil.
O erro encapsulado ainda contém o erro original dentro dele. Na próxima lição, você aprenderá a desembrulhar esses erros e verificar o que há dentro deles usando errors.Is() e errors.As().
Desafio
FácilVamos criar um sistema de processamento de pedidos que demonstre o encapsulamento de erros em várias camadas. Você criará uma cadeia de funções em que cada camada adiciona contexto aos erros, facilitando o rastreamento exato de onde os problemas ocorrem.
Você organizará seu código em dois arquivos:
orders.go: Crie a lógica de processamento de pedidos com várias camadas que encapsulam os erros à medida que eles se propagam para cima.Implemente três funções que formam uma cadeia de processamento:
ValidateItem(itemID string) error- Retorna um erro com a mensagem"item not found"se o itemID for"INVALID"; caso contrário, retornanilProcessOrder(orderID, itemID string) error- ChamaValidateItem. Se ela retornar um erro, encapsule-o com o contexto:"processing order [orderID]: %w". Caso contrário, retornenilSubmitOrder(customerName, orderID, itemID string) error- ChamaProcessOrder. Se ela retornar um erro, encapsule-o com o contexto:"submitting order for [customerName]: %w". Caso contrário, retornenil
Cada camada deve usar
fmt.Errorfcom o verbo%wpara encapsular o erro da camada abaixo, criando uma cadeia de contexto.main.go: Leia os detalhes do pedido da entrada, chameSubmitOrdere exiba o resultado. Se ocorrer um erro, imprima a cadeia completa de erros. Se a operação for bem-sucedida, imprima uma mensagem de confirmação.
As seguintes entradas serão fornecidas:
- Linha 1: Nome do cliente
- Linha 2: ID do pedido
- Linha 3: ID do item
Imprima o resultado:
- Se ocorrer um erro:
Error: [full error chain] - Se a operação for bem-sucedida:
Order [orderID] submitted successfully for [customerName]
Por exemplo, dados Alice, ORD-123 e INVALID, sua saída deverá ser:
Error: submitting order for Alice: processing order ORD-123: item not foundObserve como a mensagem de erro mostra a cadeia completa. Você pode rastrear o problema desde a tentativa de envio no nível superior, passando pelo processamento do pedido, até a falha real de validação. Cada camada adicionou seu próprio contexto usando %w.
E, dados Bob, ORD-456 e ITEM-001, sua saída deverá ser:
Order ORD-456 submitted successfully for BobExperimente você mesmo
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Ler o nome do cliente
scanner.Scan()
customerName := scanner.Text()
// Ler o ID do pedido
scanner.Scan()
orderID := scanner.Text()
// Ler o ID do item
scanner.Scan()
itemID := scanner.Text()
// TODO: Chame SubmitOrder com os valores de entrada
// TODO: Se ocorrer um erro, imprima: Error: [full error chain]
// TODO: If successful, print: Order [orderID] submitted successfully for [customerName]
_ = customerName
_ = orderID
_ = itemID
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP em Go
Arquivos ExternosWorkspace e Módulos do GoPacotes e ImportsNomes Exportados vs. Não ExportadosIntrodução à OOP em GoStructs como ClassesDefinindo Métodos em StructsReceptores de Ponteiro vs. de ValorInicialização de StructsFunções ConstrutorasRecapitulação — Calculadora Simples4Interfaces
Introdução às InterfacesImplementação ImplícitaInterface como ContratoInterface Vazia (any)Asserção de TipoSwitch de TipoComposição de InterfacesInterfaces Stringer e ErrorRecapitulação - Calculadora de Formas7Encapsulamento
Campos Exportados vs. Não ExportadosEncapsulamento no Nível de PacoteMétodos Getters e SettersOcultação de Informações em GoRecapitulação - Registros de Alunos10Genéricos (Go 1.18+)
Introdução aos genéricosParâmetros de tipoRestrições de tipoStructs genéricasAlternativa para métodos genéricosRecapitulação - Coleção genérica13Padrões de Projeto — Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão Abstract FactoryPadrão ObserverPadrão Strategy2Tipos e Structs em Profundidade
Tipos Básicos e CompostosDefinições de Tipos PersonalizadosTags de StructStructs AnônimasStructs AninhadasValores Zero e PadrõesRecapitulação - Livro de Contatos5Composição em vez de herança
Por que Go não tem herançaNoções básicas de incorporação de structsPromoção de métodosIncorporação de várias structsIncorporação vs agregaçãoOcultação de métodos incorporadosRecapitulação - Hierarquia de funcionários8Tratamento de Erros e OOP
A interface errorTipos de Erro PersonalizadosEncapsulamento de Erros (fmt.Errorf)Erros Sentinelaerrors.Is() e errors.As()Panic, Defer e RecoverRecapitulação - Analisador de Arquivos3Ponteiros e Memória
Fundamentos de Ponteiros em GoPonteiros para StructsPassagem por Valor vs. ReferênciaA Função new()Coleta de Lixo em GoRecapitulação - Construtor de Lista Ligada6Polimorfismo em Go
Polimorfismo via InterfacesDuck Typing em GoRegras de Satisfação de InterfacesColeções PolimórficasInjeção de DependênciasRecapitulação - Processador de Pagamentos9Concorrência e OOP
Fundamentos de GoroutinesCanais e comunicaçãoCanais com e sem bufferInstrução selectsync.Mutex e sync.RWMutexsync.WaitGroupDesign de structs thread-safeRevisão - Worker PoolPratique por conta própria: Compilador de Go online