actionbook/m06-tratamento-de-erros
CRÍTICO: Use para tratamento de erros. Gatilhos: Result, Option, Error, ?, unwrap, expect, panic, anyhow, thiserror, quando entrar em pânico vs retornar Result, erro personalizado, propagação de erros, tratamento de erros, uso de Result, quando usar panic
Visão Geral
Tratamento de erros é uma parte fundamental do desenvolvimento em Rust. Esta habilidade ajuda a decidir quando usar Result vs panic, como propagar erros com o operador ?, e como criar tipos de erro personalizados com as bibliotecas thiserror e anyhow.
Quando Usar Result vs panic
Result<T, E>: Use para erros recuperáveis que o chamador pode esperar e tratar (ex: arquivo não encontrado, falha de rede).panic!: Use para erros irrecuperáveis ou bugs (ex: índice fora dos limites, invariante violada).
Propagação de Erros com ?
O operador ? simplifica a propagação de erros:
use std::fs::File;
use std::io::{self, Read};
fn ler_arquivo(caminho: &str) -> io::Result<String> {
let mut arquivo = File::open(caminho)?; // Propaga erro se falhar
let mut conteudo = String::new();
arquivo.read_to_string(&mut conteudo)?;
Ok(conteudo)
}
Erros Personalizados com thiserror
thiserror é ótimo para bibliotecas onde você define tipos de erro específicos:
use thiserror::Error;
#[derive(Error, Debug)]
pub enum MeuErro {
#[error("falha ao ler arquivo: {0}")]
Io(#[from] std::io::Error),
#[error("dados inválidos: {0}")]
DadosInvalidos(String),
#[error("recurso não encontrado")]
NaoEncontrado,
}
Erros Dinâmicos com anyhow
anyhow é ideal para aplicativos que não se importam com o tipo exato do erro:
use anyhow::{Context, Result};
fn main() -> Result<()> {
let dados = std::fs::read_to_string("config.toml")
.context("falha ao ler arquivo de configuração")?;
// ...
Ok(())
}
unwrap e expect
Use unwrap e expect apenas quando você tem certeza de que o valor é Some/Ok, ou em protótipos/testes:
let valor = opcao.unwrap(); // Pânico se for `None`
let resultado = resultado.expect("mensagem personalizada"); // Pânico com mensagem
Boas Práticas
- Prefira
Resultem APIs públicas. - Use
panic!apenas para bugs ou invariantes. - Documente os erros que sua função pode retornar.
- Use
thiserrorpara bibliotecas eanyhowpara aplicações. - O operador
?é preferível aunwrap/expectna maioria dos casos.
Exemplo Completo
use anyhow::{Context, Result};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ErroProcessamento {
#[error("dados vazios")]
DadosVazios,
#[error("falha na validação: {0}")]
Validacao(String),
}
fn processar(dados: &str) -> Result<String, ErroProcessamento> {
if dados.is_empty() {
return Err(ErroProcessamento::DadosVazios);
}
// ...
Ok(dados.to_uppercase())
}
fn main() -> Result<()> {
let entrada = std::env::args().nth(1).context("argumento ausente")?;
let saida = processar(&entrada)?;
println!("{} ", saida);
Ok(())
}
Palavras-chave
Result, Option, Error, ?, unwrap, expect, panic, anyhow, thiserror, erro personalizado, propagação, tratamento de erros