💻 Exemplos: Capítulo 16: Tratamento Idiomático de Erros, Anyhow e Thiserror
💻 Exemplos: Capítulo 16: Tratamento Idiomático de Erros no Rust Corporativo
Especialização em Sistemas com Rust • Demonstrações Práticas Compiláveis
🎯 Objetivo dos Exemplos
Demonstrar a arquitetura idiomática de tratamento de erros no Rust profissional: criação de erros fortemente tipados com o padrão thiserror (ideal para bibliotecas e crates de domínio) e composição dinâmica de erros com contexto no nível de aplicação utilizando anyhow::Result e o operador ?.
1. Código Fonte Completo (src/main.rs)
//! Tratamento de Erros Corporativo: Enums Customizados e Propagação com Contexto
use std::fmt;
// 1. Definição Canônica de Erro de Domínio (Equivalente ao que a crate 'thiserror' automatiza)
#[derive(Debug)]
pub enum ErroSistemaContabil {
SaldoInsuficiente { requerido: f64, disponivel: f64 },
ContaBloqueada(String),
FalhaValidacao(String),
}
// Implementação de Display exigida pelo trait std::error::Error
impl fmt::Display for ErroSistemaContabil {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ErroSistemaContabil::SaldoInsuficiente { requerido, disponivel } => {
write!(f, "Saldo insuficiente: requisitado R$ {:.2}, mas há apenas R$ {:.2} disponível", requerido, disponivel)
}
ErroSistemaContabil::ContaBloqueada(motivo) => {
write!(f, "Conta bancária bloqueada por segurança. Motivo: {}", motivo)
}
ErroSistemaContabil::FalhaValidacao(campo) => {
write!(f, "Falha de validação estrutural no campo: '{}'", campo)
}
}
}
}
// Registro oficial no subsistema de erros da stdlib
impl std::error::Error for ErroSistemaContabil {}
// 2. Serviço de Negócio que retorna o erro fortemente tipado
struct ContaBancaria {
titular: String,
saldo: f64,
ativa: bool,
}
impl ContaBancaria {
fn sacar(&mut self, valor: f64) -> Result<f64, ErroSistemaContabil> {
if !self.ativa {
return Err(ErroSistemaContabil::ContaBloqueada(String::from("Fraude sob investigação")));
}
if valor <= 0.0 {
return Err(ErroSistemaContabil::FalhaValidacao(String::from("valor_saque_negativo")));
}
if valor > self.saldo {
return Err(ErroSistemaContabil::SaldoInsuficiente {
requerido: valor,
disponivel: self.saldo,
});
}
self.saldo -= valor;
Ok(self.saldo)
}
}
// 3. Camada de Aplicação (Padrão Anyhow com contexto adicional)
fn executar_transacao_pix(mut conta: ContaBancaria, valor: f64) -> Result<(), Box<dyn std::error::Error>> {
println!("\nProcessando transferência PIX de R$ {:.2} para {}...", valor, conta.titular);
// O operador '?' propaga o erro convertendo automaticamente para Box<dyn Error>
let novo_saldo = conta.sacar(valor)?;
println!("Transferência autorizada com sucesso! Novo saldo: R$ {:.2}", novo_saldo);
Ok(())
}
fn main() {
println!("=== TRATAMENTO IDIOMÁTICO DE ERROS EM RUST ===");
let mut conta_operacional = ContaBancaria {
titular: String::from("Empresa de Software S/A"),
saldo: 15_000.00,
ativa: true,
};
// 1. Caso de Sucesso
if let Err(e) = executar_transacao_pix(ContaBancaria { titular: conta_operacional.titular.clone(), saldo: conta_operacional.saldo, ativa: true }, 5_000.0) {
eprintln!("Erro: {}", e);
}
// 2. Caso de Erro: Saldo Insuficiente
let conta_fundos_baixos = ContaBancaria {
titular: String::from("Cliente Beta"),
saldo: 200.00,
ativa: true,
};
if let Err(e) = executar_transacao_pix(conta_fundos_baixos, 850.00) {
println!(" [FALHA DE REGRA DE NEGÓCIO CAPTURADA]");
println!(" Descrição Amigável: {}", e);
}
// 3. Caso de Erro: Conta Bloqueada
let conta_travada = ContaBancaria {
titular: String::from("Conta Suspeita"),
saldo: 100_000.00,
ativa: false,
};
if let Err(e) = executar_transacao_pix(conta_travada, 1_000.00) {
println!(" [FALHA DE CONFORMIDADE E SEGURANÇA]");
println!(" Descrição Amigável: {}", e);
}
// 4. Métodos Utilitários Funcionais do Result
println!("\nRecuperação com unwrap_or_else:");
let saldo_fallback = conta_operacional.sacar(50_000.0).unwrap_or_else(|erro| {
println!(" Operação falhou ('{}'). Adotando saldo inalterado como fallback.", erro);
conta_operacional.saldo
});
println!("Saldo após fallback: R$ {:.2}", saldo_fallback);
}
2. Saída Esperada no Terminal
=== TRATAMENTO IDIOMÁTICO DE ERROS EM RUST ===
Processando transferência PIX de R$ 5000.00 para Empresa de Software S/A...
Transferência autorizada com sucesso! Novo saldo: R$ 10000.00
Processando transferência PIX de R$ 850.00 para Cliente Beta...
[FALHA DE REGRA DE NEGÓCIO CAPTURADA]
Descrição Amigável: Saldo insuficiente: requisitado R$ 850.00, mas há apenas R$ 200.00 disponível
Processando transferência PIX de R$ 1000.00 para Conta Suspeita...
[FALHA DE CONFORMIDADE E SEGURANÇA]
Descrição Amigável: Conta bancária bloqueada por segurança. Motivo: Fraude sob investigação
Recuperação com unwrap_or_else:
Operação falhou ('Saldo insuficiente: requisitado R$ 50000.00, mas há apenas R$ 15000.00 disponível'). Adotando saldo inalterado como fallback.
Saldo após fallback: R$ 15000.00