Menu
Coddy logo textTech

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.

challenge icon

Desafio

Fácil

Vamos 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ública Profile com dois campos: username (String) e nickname (Option<String>). Implemente:
    • Um construtor new que recebe um nome de usuário e um apelido opcional
    • Um método display_name que retorna o apelido se ele existir, ou o nome de usuário como alternativa — use unwrap_or para lidar com isso
    • Um método formatted_nickname que retorna um Option<String> com o apelido envolvido em colchetes (como "[CoolNick]") se ele existir, ou None se não houver apelido — use map para transformar o valor
  • 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 de Option lidam 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: None

Você 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
}
quiz iconTeste seus conhecimentos

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