2025-03-11 13:03:04 +01:00

2.0 KiB

name = "Options" file = "src/errors/option.rs"
name = "Options" file = "src/errors/option.rs"

Sometimes, a function can fail to compute a value simply because the value you asked simply does not exist. For example, when you try to access a collection at a wrong index, or when you want to divide by zero.

To check for the existence or absence of value, we use the Option type. Option by itself is not a type, but a generic type, meaning it needs to be annotated with an other type, like this: Option<Type>. This allow us to have Option<i32>, Option<String>, Option<&str> ... And even Option<Option<i32>> if you want (but this one is a bit weird and you won't encounter it often.

Option comes in two flavors (named variants):

  • None, to encode the absence of value.
  • Some(v), to encode the presence of value. Note the v after Some to name the wrapped value.

In order to create values of type Option<T>, we just name the variant we want, and if needed, we give the variant a value:

let some_one = Some(1);
let nothing: Option<i32> = None;

To match against an Option value, you can use pattern matching:

let array = [1, 2, 3];
let element: Option<&i32> = array.first();

match element {
    None => println!("array has no first value"),
    Some(v) => println!("the first value is {}", v),
}

In this part we will try to implement usual functions of Option:

/// Returns `true` if `opt` is `Some`
/// and `false` otherwise.
pub fn is_some(opt: &Option<i32>) -> bool {
    unimplemented!()
}

/// Returns the value wrapped in `opt` if it is `Some`,
/// and `default` otherwise.
pub fn get_or_default(opt: Option<i32>, default: i32) -> i32 {
    unimplemented!()
}

/// Returns the value wrapped in `opt` if there is any,
/// and panic!() otherwise.
pub fn get_or_panic(opt: Option<i32>) -> i32 {
    unimplemented!()
}
fn main() {
    dbg!(is_some(&None)); // false
    dbg!(get_or_default(Some(5), 1)); // 5
    dbg!(get_or_panic(Some(2))); // 2
}