Lide com valores ausentes usando Option

RustBeginner
Pratique Agora

Introdução

As consultas reais nem sempre encontram um valor. O Rust representa essa possibilidade com Option<T>: Some(value) significa que existe um valor, enquanto None significa que ele não existe. Assim, a ausência faz parte do tipo, em vez de ficar escondida atrás de um número inventado ou de causar um panic.

Você vai concluir um pequeno relatório de inventário que lida com estoque encontrado e ausente, distingue um registro existente com estoque zero da ausência de um registro e usa if let quando somente o caso presente precisa de uma ação.

Faça a correspondência entre valores presentes e ausentes

Nesta etapa, você vai substituir um relatório de espaço reservado por um match exaustivo sobre o resultado de uma consulta opcional.

Entre no projeto Cargo preparado:

cd /home/labex/project/option-inventory

Abra o código-fonte:

nano src/main.rs

A função find_stock preparada retorna Option<u32>. Por enquanto, leia os sinais de menor e maior como “um Option que pode conter um u32”; a definição de tipos reutilizáveis com parâmetros entre sinais de menor e maior será ensinada mais adiante. Some(12) contém uma quantidade em estoque, enquanto None não contém quantidade alguma.

Na parte final da consulta preparada, _ => None usa o padrão curinga _. Isso significa “qualquer código que não tenha sido correspondido por um braço anterior”. O curinga não cria uma variável utilizável; ele ignora deliberadamente o valor não correspondido e retorna None.

Encontre o println! de espaço reservado dentro de report e substitua essa linha pelo seguinte match:

    match find_stock(code) {
        Some(count) => println!("{code}: {count} in stock"),
        None => println!("{code}: not found"),
    }

Some(count) reconhece um valor presente e também dá ao número interno o nome local count. O braço None trata explicitamente a ausência, portanto o match cobre todos os valores possíveis de Option<u32>.

Salve com Ctrl+O, pressione Enter e saia com Ctrl+X. Verifique o programa antes de executá-lo:

cargo check

A mensagem Finished confirma que os dois casos de Option foram cobertos. Agora execute o relatório:

cargo run --quiet

Você deverá ver:

A1: 12 in stock
B2: 0 in stock
Z9: not found

A última linha vem de None; as duas primeiras vêm de Some, incluindo o valor Some(0).

Diferencie zero de ausência

Nesta etapa, você vai dar um comportamento próprio a um registro existente com estoque zero, em vez de tratar zero como ausência.

Some(0) e None têm significados diferentes. Some(0) indica que a consulta encontrou um registro cuja quantidade é zero. None indica que não existe nenhum registro para esse código. Essa distinção mostra por que um valor de espaço reservado como 0 não é um substituto seguro para a ausência.

Abra o código-fonte novamente:

nano src/main.rs

Dentro do match em report, adicione este braço imediatamente acima do braço Some(count) existente:

        Some(0) => println!("{code}: out of stock"),

Os braços de um match são verificados de cima para baixo. O padrão específico Some(0) precisa vir antes de Some(count), porque o padrão mais amplo também corresponde a zero.

Salve e saia. Depois, execute o programa:

cargo run --quiet

A saída agora deverá ser:

A1: 12 in stock
B2: out of stock
Z9: not found

Cada linha agora representa um estado distinto: disponível, presente mas vazio ou ausente.

Aja somente quando existir um valor

Nesta etapa, você vai usar if let em uma tarefa que precisa de uma ação somente quando a consulta for bem-sucedida.

Um match exaustivo é a melhor opção quando cada caso precisa de um comportamento diferente. if let PATTERN = VALUE é uma forma concisa de correspondência condicional de padrões para a outra situação comum: executar um bloco quando um padrão corresponde e não fazer nada caso contrário.

Abra o código-fonte:

nano src/main.rs

Adicione esta função imediatamente acima de main:

fn highlight_available(code: &str) {
    if let Some(count) = find_stock(code) {
        println!("{code}: {count} available for promotion");
    }
}

O padrão só tem sucesso para Some, portanto count fica disponível dentro das chaves. Não há um bloco else porque esse auxiliar foi criado intencionalmente para não imprimir nada quando o valor for None.

Em main, remova o // inicial da linha preparada highlight_available("C3");. Salve e saia. Depois, verifique e execute o programa:

cargo check
cargo run --quiet

A saída completa deverá ser:

A1: 12 in stock
B2: out of stock
Z9: not found
C3: 5 available for promotion

A quarta linha comprova que if let extraiu o valor dentro de Some(5) sem criar um comportamento para um valor ausente.

Resumo

Você fez a correspondência entre Some e None, preservou a diferença entre Some(0) e a ausência e usou if let quando somente o caso presente exigia uma ação.