Skip to main content
eLearner.app
Module 2 · Lesson 2 of 24/14 in the course~15 min
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:

Code
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 type T.
  • None: indicates the absence of value.
Code
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 value T.
  • Err(E): the operation failed and contains the error E.
Code
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:

Code
let some_u8 = 3u8;
match some_u8 {
    1 => println!("One"),
    2 => println!("Two"),
    _ => println!("Something else"), // Handles all other values
}

Try it yourself

Exercise#rust.m2.l2.e1
Attempts: 0Loading…

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'.

Loading editor…
Show hint

Write a `match maybe_value { Some(v) => println!('value is: {}', v), None => println!('no value') }` block.

Solution available after 3 attempts

Exercise#rust.m2.l2.e2
Attempts: 0Loading…

Complete the check_age function so that it returns Ok('Adult') if age is greater than or equal to 18, and Err('Minor') otherwise.

Loading editor…
Show hint

Use `if age >= 18`to decide whether to return`Ok('Adult')`or`Err('Minor')`.

Solution available after 3 attempts

Exercise#rust.m2.l2.e3
Attempts: 0Loading…

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.

Loading editor…
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