<h2>O Tipo Result<T, E> em Rust</h2>
<p>Result é o tipo fundamental de Rust para tratamento de erros, diferente completamente do modelo de exceções. Ele é um enum que representa dois estados: sucesso (<code>Ok(T)</code>) ou falha (<code>Err(E)</code>). A principal vantagem é forçar o programador a lidar com possibilidades de erro em tempo de compilação, eliminando a surpresa de exceções não tratadas que vemos em linguagens como Java ou Python.</p>
<pre><code class="language-rust">enum Result<T, E> {
Ok(T),
Err(E),
}</code></pre>
<p>Todo Result deve ser manipulado explicitamente. Ignorar um Result gera um aviso do compilador, garantindo que você nunca "deixe passar" um erro involuntariamente. Isso torna o código mais robusto e previsível desde o início do desenvolvimento.</p>
<h2>Padrões de Tratamento Básicos</h2>
<h3>Match e Pattern Matching</h3>
<p>O <code>match</code> é a forma mais explícita de lidar com Result. Você obriga o código a considerar ambos os casos:</p>
<pre><code class="language-rust">use std::fs::File;
fn ler_arquivo(caminho: &str) -> Result<String, std::io::Error> {
let mut arquivo = File::open(caminho)?;
let mut conteudo = String::new();
arquivo.read_to_string(&mut conteudo)?;
Ok(conteudo)
}
fn main() {
match ler_arquivo("dados.txt") {
Ok(conteudo) => println!("Lido: {}", conteudo),
Err(erro) => eprintln!("Erro: {}", erro),
}
}</code></pre>
<p>O <code>match</code> é verbose mas extremamente claro. Cada branch deve retornar o mesmo tipo, o que incentiva tratamento coeso de erros.</p>
<h3>Operador <code>?</code> (Propagação)</h3>
<p>O ponto de interrogação é açúcar sintático que propaga erros automaticamente. Se uma operação falha, o erro é retornado imediatamente da função atual:</p>
<pre><code class="language-rust">fn processar_dados() -> Result<i32, Box<dyn std::error::Error>> {
let arquivo = File::open("dados.txt")?;
let numero: i32 = std::fs::read_to_string("numero.txt")?
.trim()
.parse()?;
Ok(numero * 2)
}</code></pre>
<p>O <code>?</code> só funciona em funções que retornam Result. Para <code>main()</code>, use <code>.unwrap_or_else()</code> ou retorne <code>Result</code> do main (Rust 1.26+).</p>
<h2>Métodos Essenciais de Result</h2>
<p>Result fornece métodos combinadores que permitem transformar, filtrar e processar valores sem destruir a estrutura do tipo:</p>
<pre><code class="language-rust">fn main() {
let resultado: Result<i32, String> = Ok(5);
// map: transformar o valor Ok
let dobrado = resultado.map(|x| x * 2); // Ok(10)
// map_err: transformar o erro
let erro_msg = Err::<i32, &str>("falha").map_err(|e| format!("Erro: {}", e));
// unwrap_or: valor padrão em caso de erro
let valor = Err::<i32, String>("problema".to_string()).unwrap_or(0); // 0
// and_then: acorrentar operações que retornam Result
let resultado = Ok(10)
.and_then(|x| if x > 5 { Ok(x * 2) } else { Err("muito pequeno") });
// or_else: oferecer alternativa em caso de erro
let fallback = Err::<i32, &str>("erro1")
.or_else(|_| Ok::<i32, &str>(99)); // Ok(99)
}</code></pre>
<p>Esses combinadores eliminam a necessidade de múltiplos <code>match</code> aninhados, tornando o código funcional e elegante.</p>
<h2>Erros Customizados e Boas Práticas</h2>
<h3>Definindo Tipos de Erro Próprios</h3>
<p>Para aplicações reais, crie tipos de erro específicos que implementem <code>std::error::Error</code>:</p>
<pre><code class="language-rust">use std::error::Error;
use std::fmt;
#[derive(Debug)]
enum ErroArquivo {
NaoEncontrado(String),
PermissaoNegada,
FormatoInvalido(String),
}
impl fmt::Display for ErroArquivo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ErroArquivo::NaoEncontrado(nome) =>
write!(f, "Arquivo não encontrado: {}", nome),
ErroArquivo::PermissaoNegada =>
write!(f, "Permissão negada ao acessar arquivo"),
ErroArquivo::FormatoInvalido(motivo) =>
write!(f, "Formato inválido: {}", motivo),
}
}
}
impl Error for ErroArquivo {}
fn validar_json(conteudo: &str) -> Result<(), ErroArquivo> {
if conteudo.is_empty() {
return Err(ErroArquivo::FormatoInvalido("JSON vazio".into()));
}
Ok(())
}</code></pre>
<p>Tipos de erro customizados permitem que quem chama sua função entenda exatamente quais falhas são possíveis e trate cada uma apropriadamente.</p>
<h3>Crate <code>anyhow</code> para Contexto</h3>
<p>Em projetos maiores, use a crate <code>anyhow</code> para adicionar contexto aos erros sem criar tipos complexos:</p>
<pre><code class="language-rust">// Adicione ao Cargo.toml: anyhow = "1.0"
use anyhow::{Context, Result};
fn ler_config() -> Result<String> {
let conteudo = std::fs::read_to_string("config.toml")
.context("Falha ao ler arquivo de configuração")?;
Ok(conteudo)
}
fn main() {
match ler_config() {
Ok(config) => println!("Config carregada"),
Err(e) => eprintln!("Erro: {:?}", e),
}
}</code></pre>
<p>O <code>anyhow::Result</code> é equivalente a <code>Result<T, Box<dyn Error>></code>, oferecendo flexibilidade com contexto.</p>
<h2>Conclusão</h2>
<p>Result<T, E> não é apenas um tipo — é uma filosofia de design que força você a ser explícito com erros. Os três aprendizados principais são: <strong>(1)</strong> todo erro deve ser tratado ou propagado conscientemente; <strong>(2)</strong> combinadores como <code>map</code>, <code>and_then</code> e <code>?</code> tornam o tratamento elegante e funcional; <strong>(3)</strong> erros customizados e crates como <code>anyhow</code> escalam bem em projetos reais.</p>
<p>Domine esses padrões e você escreverá código Rust robusto, previsível e mantível.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://doc.rust-lang.org/book/ch09-00-error-handling.html" target="_blank" rel="noopener noreferrer">The Rust Book - Error Handling</a></li>
<li><a href="https://doc.rust-lang.org/rust-by-example/error/result.html" target="_blank" rel="noopener noreferrer">Rust by Example - Result</a></li>
<li><a href="https://doc.rust-lang.org/std/result/" target="_blank" rel="noopener noreferrer">Documentação std::result::Result</a></li>
<li><a href="https://docs.rs/anyhow/" target="_blank" rel="noopener noreferrer">Crate anyhow</a></li>
<li><a href="https://www.lpalmieri.com/posts/error-handling-rust/" target="_blank" rel="noopener noreferrer">Error Handling in Rust - A Comprehensive Guide</a></li>
</ul>