Desempaquetar Opciones y Valores Predeterminados

RustRustBeginner
Practicar Ahora

This tutorial is from open-source community. Access the source code

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

En este laboratorio, exploraremos diferentes maneras de desempaquetar una Option y recurrir a un valor predeterminado si es None, teniendo en cuenta factores como la evaluación ágil o perezosa y si se debe modificar el valor vacío en su lugar o mantenerlo intacto.

Nota: Si el laboratorio no especifica un nombre de archivo, puede usar cualquier nombre de archivo que desee. Por ejemplo, puede usar main.rs, compilar y ejecutarlo con rustc main.rs &&./main.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/MemorySafetyandManagementGroup(["Memory Safety and Management"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/BasicConceptsGroup -.-> rust/mutable_variables("Mutable Variables") rust/DataTypesGroup -.-> rust/string_type("String Type") rust/DataTypesGroup -.-> rust/type_casting("Type Conversion and Casting") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/MemorySafetyandManagementGroup -.-> rust/lifetime_specifiers("Lifetime Specifiers") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("Method Syntax") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("Traits for Operator Overloading") subgraph Lab Skills rust/variable_declarations -.-> lab-99238{{"Desempaquetar Opciones y Valores Predeterminados"}} rust/mutable_variables -.-> lab-99238{{"Desempaquetar Opciones y Valores Predeterminados"}} rust/string_type -.-> lab-99238{{"Desempaquetar Opciones y Valores Predeterminados"}} rust/type_casting -.-> lab-99238{{"Desempaquetar Opciones y Valores Predeterminados"}} rust/function_syntax -.-> lab-99238{{"Desempaquetar Opciones y Valores Predeterminados"}} rust/expressions_statements -.-> lab-99238{{"Desempaquetar Opciones y Valores Predeterminados"}} rust/lifetime_specifiers -.-> lab-99238{{"Desempaquetar Opciones y Valores Predeterminados"}} rust/method_syntax -.-> lab-99238{{"Desempaquetar Opciones y Valores Predeterminados"}} rust/operator_overloading -.-> lab-99238{{"Desempaquetar Opciones y Valores Predeterminados"}} end

Desempaquetar opciones y valores predeterminados

Hay más de una manera de desempaquetar una Option y recurrir a un valor predeterminado si es None. Para elegir la que se ajuste a nuestras necesidades, debemos considerar lo siguiente:

  • ¿necesitamos evaluación ágil o perezosa?
  • ¿necesitamos mantener intacto el valor original vacío o modificarlo en su lugar?

or() es encadenable, evalúa de manera ágil, mantiene el valor vacío intacto

or() es encadenable y evalúa su argumento de manera ágil, como se muestra en el siguiente ejemplo. Tenga en cuenta que debido a que los argumentos de or se evalúan de manera ágil, la variable pasada a or se mueve.

#[derive(Debug)]
enum Fruit { Apple, Orange, Banana, Kiwi, Lemon }

fn main() {
    let apple = Some(Fruit::Apple);
    let orange = Some(Fruit::Orange);
    let no_fruit: Option<Fruit> = None;

    let first_available_fruit = no_fruit.or(orange).or(apple);
    println!("first_available_fruit: {:?}", first_available_fruit);
    // first_available_fruit: Some(Orange)

    // `or` mueve su argumento.
    // En el ejemplo anterior, `or(orange)` devolvió un `Some`, por lo que `or(apple)` no se invocó.
    // Pero la variable llamada `apple` se ha movido de todos modos y ya no se puede usar.
    // println!("Variable apple was moved, so this line won't compile: {:?}", apple);
    // TODO: descomente la línea anterior para ver el error del compilador
 }

or_else() es encadenable, evalúa de manera perezosa, mantiene el valor vacío intacto

Otra alternativa es usar or_else, que también es encadenable y evalúa de manera perezosa, como se muestra en el siguiente ejemplo:

#[derive(Debug)]
enum Fruit { Apple, Orange, Banana, Kiwi, Lemon }

fn main() {
    let apple = Some(Fruit::Apple);
    let no_fruit: Option<Fruit> = None;
    let get_kiwi_as_fallback = || {
        println!("Providing kiwi as fallback");
        Some(Fruit::Kiwi)
    };
    let get_lemon_as_fallback = || {
        println!("Providing lemon as fallback");
        Some(Fruit::Lemon)
    };

    let first_available_fruit = no_fruit
     .or_else(get_kiwi_as_fallback)
     .or_else(get_lemon_as_fallback);
    println!("first_available_fruit: {:?}", first_available_fruit);
    // Providing kiwi as fallback
    // first_available_fruit: Some(Kiwi)
}

get_or_insert() evalúa de manera ágil, modifica el valor vacío en su lugar

Para asegurarnos de que una Option contenga un valor, podemos usar get_or_insert para modificarla en su lugar con un valor de retorno, como se muestra en el siguiente ejemplo. Tenga en cuenta que get_or_insert evalúa su parámetro de manera ágil, por lo que la variable apple se mueve:

#[derive(Debug)]
enum Fruit { Apple, Orange, Banana, Kiwi, Lemon }

fn main() {
    let mut my_fruit: Option<Fruit> = None;
    let apple = Fruit::Apple;
    let first_available_fruit = my_fruit.get_or_insert(apple);
    println!("first_available_fruit is: {:?}", first_available_fruit);
    println!("my_fruit is: {:?}", my_fruit);
    // first_available_fruit is: Apple
    // my_fruit is: Some(Apple)
    //println!("Variable named `apple` is moved: {:?}", apple);
    // TODO: descomente la línea anterior para ver el error del compilador
}

get_or_insert_with() evalúa de manera perezosa, modifica el valor vacío en su lugar

En lugar de proporcionar explícitamente un valor de retorno, podemos pasar una clausura a get_or_insert_with, como sigue:

#[derive(Debug)]
enum Fruit { Apple, Orange, Banana, Kiwi, Lemon }

fn main() {
    let mut my_fruit: Option<Fruit> = None;
    let get_lemon_as_fallback = || {
        println!("Providing lemon as fallback");
        Fruit::Lemon
    };
    let first_available_fruit = my_fruit
     .get_or_insert_with(get_lemon_as_fallback);
    println!("first_available_fruit is: {:?}", first_available_fruit);
    println!("my_fruit is: {:?}", my_fruit);
    // Providing lemon as fallback
    // first_available_fruit is: Lemon
    // my_fruit is: Some(Lemon)

    // Si la Option tiene un valor, se deja inalterado y la clausura no se invoca
    let mut my_apple = Some(Fruit::Apple);
    let should_be_apple = my_apple.get_or_insert_with(get_lemon_as_fallback);
    println!("should_be_apple is: {:?}", should_be_apple);
    println!("my_apple is unchanged: {:?}", my_apple);
    // La salida es la siguiente. Tenga en cuenta que la clausura `get_lemon_as_fallback` no se invoca
    // should_be_apple is: Apple
    // my_apple is unchanged: Some(Apple)
}

Resumen

¡Felicitaciones! Has completado el laboratorio de Desempaquetar Opciones y Valores Predeterminados. Puedes practicar más laboratorios en LabEx para mejorar tus habilidades.