Regras de Tratamento de Erros
Bibliotecas expõem erros tipados e acionáveis; aplicativos agregam contexto e reportam para usuários e logs. Panics são para bugs, não falhas esperadas.
Receita
// biblioteca
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("não encontrado: {0}")]
NotFound(UserId),
}
// aplicativo
fn main() -> anyhow::Result<()> {
run().context("inicialização do app")?;
Ok(())
}Quando usar isso: Qualquer limite de API pública e binário main.
Exemplo Funcional
| Camada | Tipo | Contexto |
|---|---|---|
| Domínio | enum thiserror | variantes precisas |
| Adaptador | map_err para o domínio | traduz sqlx/reqwest |
| Manipulador | IntoResponse | status + JSON do problema |
| main | anyhow::Result | cadeia legível por humanos |
pub fn load_config() -> Result<Config, ConfigError> { /* ... */ }
async fn handler() -> Result<Json<User>, ApiError> {
let user = repo.get(id).await?;
Ok(Json(user))
}O que isso demonstra:
?propaga no mesmo tipo de erro ou com implFrom- Bibliotecas nunca usam
unwrapem caminhos de entrada do usuário - Aplicativos adicionam
.context("durante X")nos limites - Cadeia
source()preservada para logs
Mergulho Profundo
- Use
#[non_exhaustive]em enums de erro públicos para flexibilidade de semver anyhowapenas em binários/testes de integração, não na API pública de bibliotecas publicadasError::sourcepara encadeamento; evite erros apenas de string em bibliotecas
Armadilhas
- Erros de string em biblioteca - correspondência sem tipo. Correção: variantes de enum.
- anyhow em fn pública de biblioteca - apaga tipos para os chamadores. Correção:
Result<T, Error>concreto. - panic para validação - UX ruim. Correção:
400com mensagem. - map_err perde a origem -
.map_err(|e| e.to_string())cego. Correção:#[from]ou variantes transparentes. - ignorar erros com let _ - falhas silenciosas. Correção: logar ou propagar.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
eyre | relatórios de erro de aplicativo | API de biblioteca publicada |
| Panic | violação de invariante | Erro de digitação do usuário em formulário |
Option | verdadeiramente opcional | a operação pode falhar |
FAQs
um enum de erro por crate?
Padrão comum; submódulos usam erros aninhados #[from].
erros de serde?
Envolva serde_json::Error em uma variante de domínio com contexto.
resposta de erro axum?
Implemente IntoResponse em ApiError mapeando variantes para status.
backtrace?
RUST_BACKTRACE=1 em staging; recurso opcional de backtrace do anyhow.
tentar novamente quais erros?
Apenas erros transitórios de rede/tempo limite; não falhas de validação.
visibilidade do mod de erro?
pub use Error da raiz do crate; oculte variantes internas se necessário com tipo opaco.
erros de teste?
Corresponda a ErrorKind ou helpers de variante, não a strings Display.
no_std errors?
Impl. manual de core::fmt::Display; sem anyhow.
status grpc?
Mapeie erros de domínio para Status do tonic na camada do adaptador.
documentar erros?
Rustdoc # Errors em cada pub fn falível.
Relacionado
Versões da Stack: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4 e Polars 0.46+.