Option & Result como Enums
Option<T> modela presença ou ausência. Result<T, E> modela sucesso ou falha recuperável. Juntos, eles substituem null e exceções.
Receita
fn divide(a: f64, b: f64) -> Option<f64> {
if b == 0.0 { None } else { Some(a / b) }
}
fn read_port(s: &str) -> Result<u16, std::num::ParseIntError> {
s.parse()
}
fn main() {
println!("{:?} {:?}", divide(10.0, 2.0), read_port("8080"));
}Quando usar isso: Qualquer valor opcional (Option) e qualquer operação falível (Result).
Exemplo de Trabalho
fn first_line(path: &str) -> Result<Option<String>, std::io::Error> {
let mut lines = std::fs::read_to_string(path)?.lines();
Ok(lines.next().map(|s| s.to_string()))
}
fn main() {
match first_line("Cargo.toml") {
Ok(Some(l)) => println!("{l}"),
Ok(None) => println!("vazio"),
Err(e) => eprintln!("{e}"),
}
}O que isso demonstra:
Resultpara falha de I/OOptiondentro deOkpara arquivo vazio?propagaio::Error- Enums aninhados compõem de forma limpa
Mergulho Profundo
Definições
enum Option<T> { None, Some(T) }
enum Result<T, E> { Ok(T), Err(E) }Conversões
Option->Result:ok_or,ok_or_elseResult->Option:ok,err?emResultem funções que retornamResult
Option não é tratamento de erro
Use Result quando o chamador precisar do motivo da falha. Option para dados legitimamente ausentes.
Armadilhas
unwrapem código de biblioteca - Causa pânico no chamador. Correção: RetorneResultouOption.Nonepara erros - Perde contexto. Correção:Resultcom tipo de erro.- Misturar
?emOptionem funçãoResult- Precisa deFromouok_or. Correção:ok_or(MyError::Missing)?ou?apenas em função que retornaOption. - Tipos de erro enormes em
Result- Custo de alocação. Correção:Box<dyn Error>ou enumsthiserrorem aplicativos. - Encadeamento muito profundo sem
?- Inferno dematchaninhado. Correção:?e combinadores.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
panic! | Bug do programador, branch impossível | Falhas esperadas |
| Enum customizado | Conjunto fechado de erros no domínio | Result é suficiente |
anyhow em binários | Erros flexíveis | API pública de biblioteca |
| Valores sentinela | Nunca em APIs seguras de Rust | - |
FAQs
Por que não null?
Null confunde ausência e erro. `Option`/`Result` separam casos no nível do tipo.Coletar `Vec<Result>`?
`collect::<Result<Vec<_>, _>>()` para em curto-circuito no primeiro `Err`.`unwrap_or_default`?
Precisa de `T: Default` para o caminho `None`.Comparar Results?
Apenas se `T: PartialEq` e `E: PartialEq` - muitas vezes evitar.Blocos `try`?
Instáveis/experimentais em algumas formas - use `?` em `fn` retornando `Result`.Option em campos de struct?
Comum para registros parciais de APIs/DB.Result em iterador?
Use `Iterator<Item = Result<T,E>>` ou padrões `flatten`.Sucesso vazio?
`Result<(), E>` para operações sem valor em caso de sucesso.Option aninhado?
`Option<Option<T>>` raro - achatar com `and_then`.serde com Option?
Pula campos `None` por padrão com `skip_serializing_if`.Relacionados
- Noções Básicas de Tratamento de Erros
- O Operador ?
- Combinadores Option
- Correspondência de Padrões com match
Versões da Pilha: 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+.