The Option enum is an enum-based type in Rust that can represent one of two possible states:
This type is Rust's closest equivalent to the null and None types commonly seen in languages similar to Java and Python, respectively, and offers an easy method of handling errors involving absent values, ensuring that program crashes caused by "null" values are much harder to come across.
Think back to one of the very first examples of Rust code given in this course - if a variable is defined with an alias, but not given a value, many languages will give it a null value, whereas Rust will refuse to compile any code containing this if the variable in question is used anywhere beyond its definition.
Like any other type, Option can be specified as the return type of any given function, meaning that error handling can be easily put in place to mitigate the event of no value being found or returned.
In the case of an Option containing a value, the Some() syntax acts as a wrapper around the value, and can be removed with the built-in unwrap() method. As its name implies, this strips away the Option, in order for the value to be used elsewhere:
fn option() -> Option<i32> {
Some(10)
}
fn main() {
println!("{}", option().unwrap())
}
unwrap() is also implemented for a similar type, Result, explained on the next page.
It is important to note, however, that unwrap() assumes the value of the Option to be Some(V) with a valid value V, and calls the panic!() macro if the Option is None. As such, this should only be used in cases where the expected behaviour of a function or method returning an Option is absolutely certain, or has been manually checked beforehand.
For slightly more advanced handling of this possibility, Option has another method called expect(). This also unwraps the enum, assuming it not to be None, with the added functionality of appending a string, defined by the programmer, to any error message caused by an instance of None:
fn option() -> Option<i32> {
None
}
fn main() {
println!("{}", option().expect("shouldn't be None"))
}
In terms of pattern matching, the Option enum can be efficiently used in situations where the existence of a value needs to be confirmed:
fn main() {
let num: Option<i32> = Some(5);
match num {
Some(number) => {
println!("Number matched: {}", number)
}
None => {
println!("No value found!")
}
}
}
In the above example, the match statement uses a temporary variable number to match with the Option variable num, and prints the matching value. Furthermore, since num is explicitly defined to have an optional i32 value, all possible matches are covered (any i32, or no value), and there is no need for a wildcard match.
Exercise:
Refactor the following code so that the Option is handled without
a call to panic!():
Hint: A match statement is likely to be useful.