O Enum Option Revisitado
Parte da seção Object Oriented Programming do Journey de Rust da Coddy — lição 17 de 61.
Você já se deparou com Option<T> em Rust—é o enum padrão para representar valores que podem ou não existir. Agora vamos olhar para ele sob a ótica de POO: Option não é apenas um enum, é um tipo com métodos integrados poderosos que permitem lidar com valores anuláveis de forma segura e elegante.
Em vez de usar o matching todas as vezes, você pode usar métodos diretamente em valores Option. O método unwrap_or retorna o valor interno se ele existir, ou um padrão que você fornecer:
let maybe_name: Option<String> = Some(String::from("Alice"));
let name = maybe_name.unwrap_or(String::from("Guest"));
println!("{}", name); // Alice
let empty: Option<String> = None;
let fallback = empty.unwrap_or(String::from("Guest"));
println!("{}", fallback); // Guest
O método map transforma o valor interno se ele existir, deixando o None inalterado. Isso permite que você encadeie operações sem verificar constantemente por None:
let maybe_num: Option<i32> = Some(5);
let doubled = maybe_num.map(|x| x * 2);
println!("{:?}", doubled); // Some(10)
let nothing: Option<i32> = None;
let still_nothing = nothing.map(|x| x * 2);
println!("{:?}", still_nothing); // None
Estes métodos incorporam princípios de OOP — o tipo Option encapsula o conceito de "talvez um valor" e fornece uma interface limpa para trabalhar com ele. Você chama métodos no objeto em vez de escrever lógica externa para inspecioná-lo.
Desafio
FácilVamos construir um sistema de perfil de usuário que lida graciosamente com dados opcionais usando métodos de Option. Os usuários podem ter um apelido definido ou não — seu sistema lidará com ambos os casos de forma elegante, sem correspondência explícita (matching).
Você criará dois arquivos para organizar seu código:
profile.rs: Defina uma struct públicaProfilecom dois campos:username(String) enickname(Option<String>). Implemente:- Um construtor
newque recebe um nome de usuário e um apelido opcional - Um método
display_nameque retorna o apelido se ele existir, ou o nome de usuário como alternativa — useunwrap_orpara lidar com isso - Um método
formatted_nicknameque retorna umOption<String>com o apelido envolvido em colchetes (como"[CoolNick]") se ele existir, ouNonese não houver apelido — usemappara transformar o valor
- Um construtor
main.rs: Importe seu módulo de perfil e crie dois perfis — um com apelido e outro sem. Demonstre ambos os métodos em cada perfil para mostrar como os métodos deOptionlidam com valores presentes e ausentes de forma diferente.
Para o método formatted_nickname, use a formatação de depuração ({:?}) ao imprimir, já que ele retorna um Option.
Sua saída deve seguir este formato exato, mostrando ambos os perfis:
Display name: {name}
Formatted nickname: {option}
Display name: {name}
Formatted nickname: {option}Por exemplo, com um perfil para o nome de usuário "alice" com o apelido "Ace", e outro para o nome de usuário "bob" sem apelido, a saída seria:
Display name: Ace
Formatted nickname: Some("[Ace]")
Display name: bob
Formatted nickname: NoneVocê receberá três entradas: o primeiro nome de usuário, o apelido do primeiro usuário e o segundo nome de usuário (que não possui apelido).
Folha de consulta
O tipo Option<T> fornece métodos para trabalhar com valores opcionais sem a necessidade de correspondência (matching) explícita.
O método unwrap_or retorna o valor interno se ele existir, ou um valor padrão se for None:
let maybe_name: Option<String> = Some(String::from("Alice"));
let name = maybe_name.unwrap_or(String::from("Guest"));
println!("{}", name); // Alice
let empty: Option<String> = None;
let fallback = empty.unwrap_or(String::from("Guest"));
println!("{}", fallback); // Guest
O método map transforma o valor interno se ele existir, deixando o None inalterado:
let maybe_num: Option<i32> = Some(5);
let doubled = maybe_num.map(|x| x * 2);
println!("{:?}", doubled); // Some(10)
let nothing: Option<i32> = None;
let still_nothing = nothing.map(|x| x * 2);
println!("{:?}", still_nothing); // None
Esses métodos permitem encadear operações em valores Option sem a necessidade de verificar constantemente por None.
Experimente você mesmo
mod profile;
use profile::Profile;
fn main() {
// Ler entradas
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let username1 = input1.trim().to_string();
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let nickname1 = input2.trim().to_string();
let mut input3 = String::new();
std::io::stdin().read_line(&mut input3).expect("Failed to read line");
let username2 = input3.trim().to_string();
// TODO: Criar o primeiro perfil com username1 e nickname1 (Some)
// TODO: Criar o segundo perfil com username2 e sem apelido (None)
// TODO: Imprimir display_name e formatted_nickname para o primeiro perfil
// Use {:?} para formatted_nickname, já que ele retorna um Option
// TODO: Imprimir display_name e formatted_nickname para o segundo perfil
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Object Oriented Programming
1Métodos e Comportamento
Introdução a Blocos de ImplementaçãoO Parâmetro SelfMétodos MutáveisFunções AssociadasMúltiplos Blocos de ImplementaçãoEncadeamento de MétodosRecapitulação - Ações de Retângulo4Projeto: Pet Virtual
Definindo o PetAlimentando o Pet7Traits Padrão
A Trait DebugA Trait DisplayClone e CopyTraits de IgualdadeRecapitulação - Ponto Imprimível10Projeto: Sistema de Documentos
A Trait DrawComponente de Texto2Encapsulamento e Módulos
Fundamentos de MódulosA Palavra-chave PublicCampos PrivadosGettersSettersRecapitulação - Cofre Seguro5Genéricos
Structs GenéricasMétodos GenéricosMúltiplos Tipos GenéricosFunções GenéricasRecapitulação - Ponto de Coordenada8Traits como Restrições
Sintaxe de Restrições de TraitRestrições MúltiplasA Cláusula WhereRetornando Tipos com TraitsRecapitulação - Impressora Genérica11Padrões de Projeto em Rust
Padrão NewtypeComposiçãoA Trait DropFrom e IntoRecapitulação - Mock de Smart Pointer3Enums Avançados
Enums com DadosMétodos em EnumsCorrespondência de Variantes de DadosO Enum Option RevisitadoRecapitulação - Enum Shape6Definição de Traits
O que é uma Trait?Implementando TraitsImplementações PadrãoSobrescrevendo PadrõesTraits com ParâmetrosRecapitulação - Media Player