O Enum Option Revisitado
Parte da seção Programação Orientada a Objetos do Journey de Rust da Coddy. Lição 17 de 61.
Você já encontrou Option<T> em Rust: é o enum padrão para representar valores que podem ou não existir. Agora vamos analisá-lo sob a perspectiva da OOP: Option não é apenas um enum, é um tipo com métodos integrados poderosos que permitem lidar com valores nulos de forma segura e elegante.
Em vez de fazer correspondências todas as vezes, você pode usar métodos diretamente em valores de Option. O método unwrap_or retorna o valor interno se ele existir ou um valor 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, mantendo None inalterado. Isso permite encadear operações sem verificar constantemente se há 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
Esses métodos incorporam os princípios de OOP: o tipo Option encapsula o conceito de "talvez um valor" e fornece uma interface clara para trabalhar com ele. Você chama métodos no objeto em vez de escrever lógica externa para inspecioná-lo.
Desafio
FácilVamos criar um sistema de perfil de usuário que lida adequadamente com dados opcionais usando métodos de Option. Os usuários podem ter um apelido definido ou podem não ter. Seu sistema lidará elegantemente com ambos os casos, sem correspondência explícita.
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 entre colchetes (como"[CoolNick]") se ele existir, ouNonese não houver apelido: usemappara transformar o valor
- Um construtor
main.rs: Inclua 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 de maneira diferente com valores presentes e ausentes.
Para o método formatted_nickname, use a formatação de depuração ({:?}) ao imprimir, pois ele retorna um Option.
Sua saída deve seguir exatamente este formato, 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 tem apelido).
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: Create second profile with username2 and no nickname (None)
// TODO: Print display_name and formatted_nickname for first profile
// Use {:?} for formatted_nickname since it returns an Option
// TODO: Print display_name and formatted_nickname for second profile
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
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 PlayerPratique por conta própria: Compilador de Rust online