O que é Option<T>
Option<T> é o tipo que Rust usa para representar valores que podem ou não existir. Ele tem exatamente duas variantes: Some(T) quando há um valor presente, e None quando não há. Diferente de linguagens que usam null ou nil, o Option força você a lidar explicitamente com a ausência de valor, eliminando a categoria inteira de erros de null pointer em tempo de compilação.
Use Option<T> sempre que uma função pode não retornar um resultado (busca em uma coleção, parsing opcional, primeiro elemento de uma lista vazia), ou quando um campo de uma struct é opcional. Praticamente todo código Rust usa Option intensivamente — ele está no prelude e pode ser usado sem importar nada.
Criando e Usando Option
fn main() {
// Criando diretamente
let algum_valor: Option<i32> = Some(42);
let nenhum_valor: Option<i32> = None;
// Retornado por métodos da stdlib
let numeros = vec![10, 20, 30];
let primeiro: Option<&i32> = numeros.first(); // Some(&10)
let decimo: Option<&i32> = numeros.get(9); // None
let texto = "42abc";
let resultado: Option<usize> = texto.find('a'); // Some(2)
// Pattern matching — a forma mais completa
match primeiro {
Some(valor) => println!("Primeiro: {valor}"),
None => println!("Lista vazia"),
}
// if let — quando só interessa o caso Some
if let Some(pos) = resultado {
println!("Encontrado na posição {pos}");
}
// let-else — quando None é o caso de erro (Rust 1.65+)
let Some(val) = algum_valor else {
println!("Sem valor!");
return;
};
println!("Valor: {val}");
println!("{nenhum_valor:?} {decimo:?}");
}
Tabela de Métodos Principais
| Método | Descrição | Exemplo |
|---|---|---|
is_some() | Retorna true se é Some | Some(1).is_some() → true |
is_none() | Retorna true se é None | None::<i32>.is_none() → true |
unwrap() | Extrai o valor ou panic | Some(1).unwrap() → 1 |
unwrap_or(default) | Extrai ou retorna default | None.unwrap_or(0) → 0 |
unwrap_or_else(f) | Extrai ou calcula via closure | None.unwrap_or_else(|| calcular()) |
unwrap_or_default() | Extrai ou usa Default::default() | None::<i32>.unwrap_or_default() → 0 |
expect(msg) | Como unwrap mas com mensagem de panic | opt.expect("erro") |
map(f) | Transforma o valor interno | Some(1).map(|x| x * 2) → Some(2) |
map_or(default, f) | Transforma ou retorna default | None.map_or(0, |x| x * 2) → 0 |
and_then(f) | Encadeia operações que retornam Option | Some(1).and_then(|x| Some(x + 1)) |
filter(pred) | None se o predicado falhar | Some(4).filter(|x| x % 2 == 0) → Some(4) |
or(outra) | Retorna self se Some, senão outra | None.or(Some(5)) → Some(5) |
or_else(f) | Como or, mas com closure | None.or_else(|| Some(5)) |
zip(outra) | Combina dois Options em tupla | Some(1).zip(Some("a")) → Some((1, "a")) |
flatten() | Achata Option<Option<T>> | Some(Some(1)).flatten() → Some(1) |
ok_or(err) | Converte para Result<T, E> | Some(1).ok_or("erro") → Ok(1) |
ok_or_else(f) | Converte para Result com closure | None.ok_or_else(|| "erro") |
as_ref() | Option<&T> a partir de &Option<T> | opt.as_ref() |
take() | Pega o valor, deixando None | opt.take() |
replace(val) | Substitui o valor, retornando o antigo | opt.replace(5) |
Exemplos Práticos
1. Encadeando Transformações com map e and_then
fn buscar_usuario(id: u64) -> Option<String> {
match id {
1 => Some("Ana Silva".to_string()),
2 => Some("Bruno Costa".to_string()),
_ => None,
}
}
fn extrair_primeiro_nome(nome_completo: &str) -> Option<&str> {
nome_completo.split_whitespace().next()
}
fn main() {
// Encadeando operações que podem falhar
let saudacao = buscar_usuario(1)
.as_deref() // Option<String> → Option<&str>
.and_then(extrair_primeiro_nome)
.map(|nome| format!("Olá, {nome}!"))
.unwrap_or_else(|| "Usuário não encontrado".to_string());
println!("{saudacao}"); // "Olá, Ana!"
// Com usuário inexistente
let saudacao2 = buscar_usuario(99)
.as_deref()
.and_then(extrair_primeiro_nome)
.map(|nome| format!("Olá, {nome}!"))
.unwrap_or_else(|| "Usuário não encontrado".to_string());
println!("{saudacao2}"); // "Usuário não encontrado"
}
2. O Operador ? com Option
#[derive(Debug)]
struct Endereco {
rua: String,
numero: Option<u32>,
complemento: Option<String>,
}
#[derive(Debug)]
struct Pessoa {
nome: String,
endereco: Option<Endereco>,
}
fn obter_complemento(pessoa: &Pessoa) -> Option<&str> {
// O operador ? retorna None imediatamente se qualquer etapa for None
pessoa
.endereco
.as_ref()?
.complemento
.as_deref()
}
fn main() {
let pessoa1 = Pessoa {
nome: "Ana".into(),
endereco: Some(Endereco {
rua: "Rua das Flores".into(),
numero: Some(42),
complemento: Some("Apto 301".into()),
}),
};
let pessoa2 = Pessoa {
nome: "Bruno".into(),
endereco: None,
};
println!("{}: {:?}", pessoa1.nome, obter_complemento(&pessoa1)); // Some("Apto 301")
println!("{}: {:?}", pessoa2.nome, obter_complemento(&pessoa2)); // None
}
3. Convertendo entre Option e Result
use std::num::ParseIntError;
fn buscar_config(chave: &str) -> Option<String> {
match chave {
"porta" => Some("8080".to_string()),
"host" => Some("localhost".to_string()),
_ => None,
}
}
fn obter_porta() -> Result<u16, String> {
buscar_config("porta")
.ok_or_else(|| "Chave 'porta' não encontrada".to_string())?
.parse::<u16>()
.map_err(|e: ParseIntError| format!("Porta inválida: {e}"))
}
fn main() {
match obter_porta() {
Ok(porta) => println!("Servidor rodando na porta {porta}"),
Err(erro) => eprintln!("Erro: {erro}"),
}
}
4. Combinando Múltiplos Options com zip
fn calcular_imc(peso_kg: Option<f64>, altura_m: Option<f64>) -> Option<f64> {
peso_kg
.zip(altura_m)
.filter(|(_, a)| *a > 0.0)
.map(|(p, a)| p / (a * a))
}
fn classificar_imc(imc: f64) -> &'static str {
match imc {
x if x < 18.5 => "Abaixo do peso",
x if x < 25.0 => "Peso normal",
x if x < 30.0 => "Sobrepeso",
_ => "Obesidade",
}
}
fn main() {
let resultado = calcular_imc(Some(70.0), Some(1.75))
.map(|imc| format!("IMC: {imc:.1} - {}", classificar_imc(imc)))
.unwrap_or_else(|| "Dados insuficientes".to_string());
println!("{resultado}"); // "IMC: 22.9 - Peso normal"
let incompleto = calcular_imc(Some(70.0), None);
println!("{incompleto:?}"); // None
}
5. Coletando Options em um Vec
fn main() {
let entradas = vec!["42", "abc", "7", "xyz", "100"];
// collect() descarta os None automaticamente com flatten
let numeros: Vec<i32> = entradas
.iter()
.map(|s| s.parse::<i32>().ok()) // Cada parse retorna Option<i32>
.flatten() // Remove os None
.collect();
println!("Números: {numeros:?}"); // [42, 7, 100]
// Alternativa com filter_map (equivalente a map + flatten)
let numeros2: Vec<i32> = entradas
.iter()
.filter_map(|s| s.parse().ok())
.collect();
println!("Números: {numeros2:?}"); // [42, 7, 100]
// collect() que falha no primeiro None
let todos: Option<Vec<i32>> = vec!["1", "2", "3"]
.iter()
.map(|s| s.parse().ok())
.collect();
println!("Todos: {todos:?}"); // Some([1, 2, 3])
let com_falha: Option<Vec<i32>> = vec!["1", "abc", "3"]
.iter()
.map(|s| s.parse().ok())
.collect();
println!("Com falha: {com_falha:?}"); // None
}
Dicas de Performance e Armadilhas
Evite
unwrap()em produção: Useunwrap()apenas em testes, protótipos ou quando tiver certeza absoluta de que o valor éSome. Prefiraunwrap_or,unwrap_or_else, ou pattern matching.mapvsand_then: Usemapquando a transformação sempre retorna um valor. Useand_thenquando a transformação também pode falhar (retornaOption). Usarmapcom uma função que retornaOptiongeraOption<Option<T>>.Custo zero:
Option<T>não tem overhead de memória quandoTé uma referência ouNonZero*. O compilador usa a representação nula paraNone, eliminando o byte extra.as_ref()para evitar movimentos: Quando tiver&Option<T>e precisar deOption<&T>, useas_ref(). Isso evita mover o valor para fora do Option.take()para extrair valores:option.take()substitui o valor porNonee retorna o antigo. Útil quando precisa mover o valor de dentro de uma struct sem clonar.Optionem iteradores: Iteradores possuem métodos comofilter_mapefindque trabalham naturalmente comOption, evitando verificações manuais.
Veja Também
- Tratamento de Erros em Rust — tutorial completo com Option e Result
- Result<T,E>: Ok e Err — o tipo irmão para erros recuperáveis
- Iterator Trait — trabalha intensivamente com Option
- HashMap<K,V> —
get()retornaOption<&V> - Vec<T> —
first(),last(),get()retornam Option - Cheatsheet Rust — referência rápida de sintaxe
- Documentação oficial — std::option::Option