Zoeken…


Invoering

Het type Option<T> is het equivalent van Rust van nulbare typen, zonder alle problemen die daarbij horen. Bij de meeste C-achtige talen kan elke variabele null als er geen gegevens aanwezig zijn, maar het Option is geïnspireerd op functionele talen die 'optionals' prefereren (bijv. Haskell's Maybe monade). Met Option kunt u het idee uitdrukken dat er al dan niet gegevens zijn (aangezien Rust geen nulbare typen heeft).

Een optiewaarde en patroonovereenkomst maken

// The Option type can either contain Some value or None.
fn find(value: i32, slice: &[i32]) -> Option<usize> {
    for (index, &element) in slice.iter().enumerate() {
        if element == value {
            // Return a value (wrapped in Some).
            return Some(index);
        }
    }
    // Return no value.
    None
}

fn main() {
    let array = [1, 2, 3, 4, 5];
    // Pattern match against the Option value.
    if let Some(index) = find(2, &array) {
        // Here, there is a value.
        println!("The element 2 is at index {}.", index);
    }

    // Check if the result is None (no value).
    if let None = find(12, &array) {
        // Here, there is no value.
        println!("The element 12 is not in the array.");
    }

    // You can also use `is_some` and `is_none` helpers
    if find(12, &array).is_none() {
        println!("The element 12 is not in the array.");
    }
}

Een optie vernietigen

fn main() {
    let maybe_cake = Some("Chocolate cake");
    let not_cake = None;

    // The unwrap method retrieves the value from the Option
    // and panics if the value is None
    println!("{}", maybe_cake.unwrap());

    // The expect method works much like the unwrap method,
    // but panics with a custom, user provided message.
    println!("{}", not_cake.expect("The cake is a lie."));

    // The unwrap_or method can be used to provide a default value in case
    // the value contained within the option is None. This example would
    // print "Cheesecake".
    println!("{}", not_cake.unwrap_or("Cheesecake"));

    // The unwrap_or_else method works like the unwrap_or method,
    // but allows us to provide a function which will return the
    // fallback value. This example would print "Pumpkin Cake".
    println!("{}", not_cake.unwrap_or_else(|| { "Pumpkin Cake" }));

    // A match statement can be used to safely handle the possibility of none.
    match maybe_cake {
        Some(cake) => println!("{} was consumed.", cake),
        None       => println!("There was no cake.")
    }

    // The if let statement can also be used to destructure an Option.
    if let Some(cake) = maybe_cake {
        println!("{} was consumed.", cake);
    }
}

Verwijdering van een verwijzing naar een optie die de inhoud bezit

Een verwijzing naar een optie &Option<T> kan niet worden uitgepakt als het type T niet kan worden gekopieerd. De oplossing is om de optie te wijzigen in &Option<&T> met behulp van as_ref() .

Roest verbiedt de overdracht van eigendom van objecten terwijl de objecten worden geleend. Wanneer de Optie zelf wordt geleend ( &Option<T> ), wordt de inhoud ook - indirect - geleend.

#[derive(Debug)]
struct Foo;
 
fn main() {
    let wrapped = Some(Foo);
    let wrapped_ref = &wrapped;
    
    println!("{:?}", wrapped_ref.unwrap()); // Error!
}

kan geleende inhoud niet verplaatsen [--explain E0507]

Het is echter mogelijk om een verwijzing naar de inhoud van Option<T> . De methode as_ref() Option retourneert een optie voor &T , die kan worden uitgepakt zonder eigendomsoverdracht:

println!("{:?}", wrapped_ref.as_ref().unwrap());

Optie met kaart en anden gebruiken

De map operatie is een handig hulpmiddel bij het werken met arrays en vectoren, maar het kan ook worden gebruikt om te gaan met Option waarden in een functionele manier.

fn main() {

    // We start with an Option value (Option<i32> in this case).
    let some_number = Some(9);

    // Let's do some consecutive calculations with our number.
    // The crucial point here is that we don't have to unwrap
    // the content of our Option type - instead, we're just
    // transforming its content. The result of the whole operation
    // will still be an Option<i32>. If the initial value of
    // 'some_number' was 'None' instead of 9, then the result
    //  would also be 'None'.
    let another_number = some_number
        .map(|n| n - 1) // => Some(8)
        .map(|n| n * n) // => Some(64)
        .and_then(|n| divide(n, 4)); // => Some(16)

    // In the last line above, we're doing a division using a helper
    // function (definition: see bottom).
    // 'and_then' is very similar to 'map', but allows us to pass a
    // function which returns an Option type itself. To ensure that we
    // don't end up with Option<Option<i32>>, 'and_then' flattens the
    // result (in other languages, 'and_then' is also known as 'flatmap').

    println!("{}", to_message(another_number));
    // => "16 is definitely a number!"

    // For the sake of completeness, let's check the result when
    // dividing by zero.
    let final_number = another_number
        .and_then(|n| divide(n, 0)); // => None

    println!("{}", to_message(final_number));
    // => "None!"
}

// Just a helper function for integer division. In case
// the divisor is zero, we'll get 'None' as result.
fn divide(number: i32, divisor: i32) -> Option<i32> {
    if divisor != 0  { Some(number/divisor) } else { None }
}

// Creates a message that tells us whether our
// Option<i32> contains a number or not. There are other
// ways to achieve the same result, but let's just use
// map again!
fn to_message(number: Option<i32>) -> String {
    number
        .map(|n| format!("{} is definitely a number!", n)) // => Some("...")
        .unwrap_or("None!".to_string()) // => "..."
}


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow