Gestionar valores ausentes con Option

RustBeginner
Practicar Ahora

Introducción

Las búsquedas reales no siempre encuentran un valor. Rust representa esta posibilidad con Option<T>: Some(value) significa que existe un valor, mientras que None significa que no existe. De este modo, la ausencia forma parte del tipo, en lugar de ocultarse detrás de un número inventado o provocar un error de ejecución.

Completará un pequeño informe de inventario que gestiona existencias encontradas y ausentes, distingue entre un registro existente con cero unidades y la ausencia de un registro, y utiliza if let cuando solo es necesario realizar una acción en el caso de que exista un valor.

Coincidir valores presentes y ausentes

En este paso, sustituirá un informe provisional por una coincidencia exhaustiva sobre el resultado opcional de una búsqueda.

Acceda al proyecto de Cargo preparado:

cd /home/labex/project/option-inventory

Abra el código fuente:

nano src/main.rs

La función find_stock preparada devuelve Option<u32>. Por ahora, interprete los corchetes angulares como “un Option que puede contener un u32”; más adelante aprenderá a definir tipos reutilizables con parámetros entre corchetes angulares. Some(12) contiene una cantidad de existencias, mientras que None no contiene ninguna cantidad.

Al final de la búsqueda preparada, _ => None utiliza el patrón comodín _. Esto significa “cualquier código que no haya coincidido con un brazo anterior”. El comodín no crea una variable utilizable; ignora deliberadamente el valor no coincidente y devuelve None.

Busque el println! provisional dentro de report y sustituya esa línea por esta coincidencia:

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

Some(count) reconoce un valor presente y, al mismo tiempo, asigna a su número interno el nombre local count. El brazo None gestiona explícitamente la ausencia, por lo que la coincidencia cubre todos los valores posibles de Option<u32>.

Guarde el archivo con Ctrl+O, pulse Enter y salga con Ctrl+X. Compruebe el programa antes de ejecutarlo:

cargo check

El mensaje Finished confirma que se han cubierto los dos casos de Option. Ahora ejecute el informe:

cargo run --quiet

Debería ver lo siguiente:

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

La última línea procede de None; las dos primeras proceden de Some, incluido el valor Some(0).

Distinguir cero de ausencia

En este paso, asignará un comportamiento propio a un registro existente con cero unidades, en lugar de tratar el cero como una ausencia.

Some(0) y None significan cosas distintas. Some(0) indica que la búsqueda encontró un registro cuya cantidad es cero. None indica que no existe ningún registro para ese código. Por eso un valor provisional como 0 no es un sustituto seguro de la ausencia.

Abra de nuevo el código fuente:

nano src/main.rs

Dentro de la coincidencia de report, añada este brazo justo encima del brazo Some(count) existente:

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

Los brazos de una coincidencia se comprueban de arriba abajo. El patrón específico Some(0) debe aparecer antes que Some(count), porque el patrón más amplio también coincide con cero.

Guarde y salga; después, ejecute el programa:

cargo run --quiet

Ahora la salida debería ser:

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

Cada línea representa ahora un estado distinto: disponible, presente pero vacío, o ausente.

Actuar solo cuando existe un valor

En este paso, utilizará if let para una tarea que solo necesita realizar una acción cuando la búsqueda tiene éxito.

Una coincidencia exhaustiva con match es adecuada cuando cada caso requiere un comportamiento diferente. if let PATTERN = VALUE es una forma concisa de coincidencia condicional para la otra situación habitual: ejecutar un bloque cuando un patrón coincide y no hacer nada en caso contrario.

Abra el código fuente:

nano src/main.rs

Añada esta función justo encima de main:

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

El patrón solo coincide con Some, por lo que count está disponible dentro de las llaves. No hay ningún bloque else porque esta función auxiliar no debe imprimir nada intencionadamente cuando recibe None.

En main, elimine los caracteres iniciales // de la línea preparada highlight_available("C3");. Guarde y salga; después, compruebe y ejecute el programa:

cargo check
cargo run --quiet

La salida completa debería ser:

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

La cuarta línea demuestra que if let extrajo el valor contenido en Some(5) sin inventar ningún comportamiento para un valor ausente.

Resumen

Coincidió Some y None, conservó la diferencia entre Some(0) y la ausencia, y utilizó if let cuando solo el caso presente requería una acción.