Module lessons (2/2)
Pattern Matching, Option, and Result
Rust has an extremely powerful control flow mechanism called pattern matching. It allows you to compare a value against a series of patterns and execute code based on which pattern matches.
The match Statement
The match statement in Rust is similar to a switch in other languages, but much more powerful and safe. The compiler ensures that the match is exhaustive, meaning all possible cases must be handled:
enum Direction {
North,
South,
East,
West,
}
let dir = Direction::East;
match dir {
Direction::North => println!("Andiamo a Nord"),
Direction::South => println!("Andiamo a Sud"),
Direction::East => println!("Andiamo a Est"),
Direction::West => println!("Andiamo a Ovest"),
}
Handling Absence of Value: Option
Rust does not have the concept of a null value (null or nil). Instead, the standard library defines an enum called Option<T> which can contain:
Some(T): contains a value of typeT.None: indicates the absence of value.
let x: Option<i32> = Some(5);
let y: Option<i32> = None;
match x {
Some(val) => println!("C'e un valore: {}", val),
None => println!("Nessun valore trovato"),
}
Handling Recoverable Errors: Result
For operations that can fail (like reading a file or parsing a string into a number), Rust uses the Result<T, E> enum, which has two variants:
Ok(T): the operation succeeded and contains the success valueT.Err(E): the operation failed and contains the errorE.
fn divide(numerator: f64, denominator: f64) -> Result<f64, String> {
if denominator == 0.0 {
Err(String::from("Divisione per zero!"))
} else {
Ok(numerator / denominator)
}
}
Thanks to Rust's compiler, you are forced to handle the Err case before you can access the value inside Ok, preventing many common runtime bugs.
The Wildcard Pattern _
When working with data types that have a large number of variants (like integers), listing all cases in a match is impossible. Rust allows using the wildcard character _ to catch all remaining cases not explicitly defined:
let some_u8 = 3u8;
match some_u8 {
1 => println!("One"),
2 => println!("Two"),
_ => println!("Something else"), // Handles all other values
}
Try it yourself
Declare a variable named maybe_value of type Option<i32> containing Some(42). Use a match statement on maybe_value: if it contains Some(v) print 'value is: v' (using println!), if it contains None print 'no value'.
Show hint
Write a `match maybe_value { Some(v) => println!('value is: {}', v), None => println!('no value') }` block.
Solution available after 3 attempts
Complete the check_age function so that it returns Ok('Adult') if age is greater than or equal to 18, and Err('Minor') otherwise.
Show hint
Use `if age >= 18`to decide whether to return`Ok('Adult')`or`Err('Minor')`.
Solution available after 3 attempts
Declare an enum named Status containing the variants Active and Inactive. In main, declare a variable current_status with the value Status::Active. Finally, use a match statement on current_status to print 'active' if the status is Active, or 'inactive' if the status is Inactive.
Show hint
Define the enum before main with `enum Status { Active, Inactive }`. In main, use `let current_status = Status::Active;`and perform the`match` on the variants.
Solution available after 3 attempts