💻 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