Luis Tavarez · Noticias

Rust: ownership e iteradores sin clonar las órdenes

Compara un bucle y try_fold sobre un slice prestado. Comprueba que conservas la entrada y detectas el desbordamiento.

Luis Tavarez ·

Leer no exige transferir la propiedad

Las dos funciones reciben un slice prestado de órdenes. main conserva el vector y puede consultarlo después de calcular el total. No se usa clone para eludir el diseño de propiedad ni se necesita compartir estado mutable.

Dos implementaciones del mismo contrato

El bucle acumula con checked_add. La versión con iteradores filtra órdenes pagadas y usa try_fold con la misma suma comprobada. Ambas devuelven Option: Some contiene el total y None expresa un desbordamiento.

El operador de propagación dentro del bucle devuelve None si una suma falla. El iterador hace lo equivalente a través de try_fold. No debes reemplazar checked_add por una suma que dependa del comportamiento de overflow del perfil de compilación.

Pruebas que acompañan la decisión

El programa comprueba un conjunto normal, la entrada vacía y dos valores que exceden u64. Por último vuelve a usar orders, demostrando que el préstamo no transfirió la propiedad. No mide throughput ni demuestra que una forma sea más rápida.

Llevarlo a un servicio

Una respuesta HTTP podría mapear None a un error de dominio explícito. Si necesitas explicar distintas causas, cambia Option por Result con un tipo de error. Concurrencia, I/O y transacciones quedan fuera de este cálculo puro; los préstamos no resuelven por sí mismos la coordinación entre servicios.

Rust · Laboratorio para desarrolladores

Arquitectura, código y práctica

LT Architecture StudioDiagrama creado con nuestra herramienta. Explóralo y adáptalo a tu proyecto.
Rust: ownership e iteradores sin clonar las órdenes

Ejecutar el ejemplo

Rust estable con rustc. El ejemplo usa la edición 2021, biblioteca estándar y ninguna dependencia Cargo. En Windows ejecuta example.exe tras compilar.

rustc --edition 2021 main.rs -o example
./example

Salida esperada: OK: borrowed input preserved; overflow rejected

Código del ejemplo
rust
#[derive(Debug)]
struct Order { cents: u64, paid: bool }

fn total_loop(orders: &[Order]) -> Option<u64> {
    let mut total = 0_u64;
    for order in orders {
        if order.paid { total = total.checked_add(order.cents)?; }
    }
    Some(total)
}

fn total_iter(orders: &[Order]) -> Option<u64> {
    orders.iter().filter(|order| order.paid)
        .try_fold(0_u64, |sum, order| sum.checked_add(order.cents))
}

fn main() {
    let orders = vec![
        Order { cents: 1200, paid: true },
        Order { cents: 700, paid: false },
        Order { cents: 800, paid: true },
    ];
    assert_eq!(total_loop(&orders), Some(2000));
    assert_eq!(total_iter(&orders), Some(2000));
    assert_eq!(total_iter(&[]), Some(0));
    let overflow = [Order { cents: u64::MAX, paid: true }, Order { cents: 1, paid: true }];
    assert_eq!(total_loop(&overflow), None);
    assert_eq!(total_iter(&overflow), None);
    // Both functions borrowed the slice; ownership remains here.
    assert_eq!(orders.len(), 3);
    println!("OK: borrowed input preserved; overflow rejected");
}

Ejercicio para continuar

Cambia Option por Result con un error Overflow. Conserva los casos normal, vacío y desbordamiento, sin clonar el vector.