Tratamento de Erros em Rust: try/catch e além — nível avançado

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Tratamento de Erros em Rust: try/catch e além — nível avançado

\n\n

Ao contrário de muitas linguagens onde exceções são o mecanismo padrão (como try/catch em Python, Java ou C++), Rust oferece uma abordagem fundamentalmente diferente. Aqui não existem exceções no sentido clássico. Em vez disso, a linguagem usa um poderoso sistema de tipos para representar e tratar erros. Para um iniciante, isso pode parecer complexo, mas em um nível avançado, você apreciará a segurança e previsibilidade que essa abordagem proporciona. Neste artigo, vamos explorar como trabalhar com erros em Rust profissionalmente: desde os básicos Result e Option até os crates avançados anyhow e thiserror, além de traçar paralelos com o familiar try/catch.

\n\n

1. Fundamentos: Result, Option e o operador ?

\n\n

A base do tratamento de erros em Rust é a enumeração Result<T, E>. Ela pode ser Ok(T) (sucesso) ou Err(E) (erro). O análogo ao try/catch pode ser considerado o operador ?. Ele simplifica o encaminhamento do erro para cima: se o valor for Err, a função o retorna imediatamente; se for Ok, extrai o valor.

\n\n
use std::fs::File;\nuse std::io::Read;\n\nfn read_file(path: &str) -> Result<String, std::io::Error> {\n    let mut file = File::open(path)?; // Análogo ao try: encaminhamento do erro\n    let mut content = String::new();\n    file.read_to_string(&mut content)?;\n    Ok(content)\n}
\n\n

Neste exemplo, File::open e read_to_string podem retornar Err. O operador ? substitui o verboso match e torna o código limpo, como try/catch em outras linguagens. No entanto, ao contrário das exceções, você especifica explicitamente o tipo de erro na assinatura da função — isso aumenta a legibilidade e a segurança.

\n\n

A enumeração Option<T> é usada para casos onde um valor pode estar ausente (análogo ao None em Python). O operador ? também funciona com ela:

\n\n
fn get_first_element(vec: &Vec<i32>) -> Option<&i32> {\n    vec.first()? // Se o vetor estiver vazio, retorna None\n}
\n\n

2. Trabalho avançado com tipos de erro: traits From e Error

\n\n

Quando uma função chama várias operações com diferentes tipos de erro (por exemplo, entrada/saída e parsing), surge um problema: como retornar um tipo único? A solução é o trait From e um tipo de erro personalizado.

\n\n

Vamos criar nossa própria estrutura de erro e implementar o trait std::error::Error para ela (automaticamente via #[derive(Debug)] e implementação manual de Display):

\n\n
use std::fmt;\nuse std::io;\n\n#[derive(Debug)]\nenum MyError {\n    Io(io::Error),\n    Parse(std::num::ParseIntError),\n}\n\nimpl fmt::Display for MyError {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match self {\n            MyError::Io(e) => write!(f, "Erro de IO: {}", e),\n            MyError::Parse(e) => write!(f, "Erro de parsing: {}", e),\n        }\n    }\n}\n\nimpl std::error::Error for MyError {}\n\n// Implementamos From para conversão automática\nimpl From<io::Error> for MyError {\n    fn from(error: io::Error) -> Self {\n        MyError::Io(error)\n    }\n}\n\nimpl From<std::num::ParseIntError> for MyError {\n    fn from(error: std::num::ParseIntError) -> Self {\n        MyError::Parse(error)\n    }\n}\n\nfn process_data(path: &str) -> Result<i32, MyError> {\n    let content = std::fs::read_to_string(path)?; // Converte automaticamente para MyError::Io\n    let number: i32 = content.trim().parse()?;    // Converte automaticamente para MyError::Parse\n    Ok(number)\n}
\n\n

Agora a função process_data retorna um tipo único MyError, e o operador ? converte automaticamente os erros graças ao trait implementado

Blogs

Book Recommendations