Patterns

https://doc.rust-lang.org/reference/patterns.html

Patterns are pieces of syntax which are used to match values against different variants of a type and constants/literals, optionally destructuring and binding internal values to names.

We define two types of patterns in Rust:

  • refutable
  • irrefutable

Irrefutable patterns are such patterns that are always true. We can use the let binding to demonstrate these:

#![allow(unused)]
fn main() {
// bind to identifier - works for any value of any type
let my_bidning = 33;

// destructuring a tuple
let (first, second) = (33, 33);

// the unit type has only one value, the unit itself

let () = ();

// similar case with a unit struct
struct Empty;

let Empty = Empty;

// destructuring a structure
struct Point {
    x: isize,
    y: isize,
}

// x and y are now defined bindings
let Point { x, y } = Point { x: 24, y: 23 };

// you can also rename
let Point { x: other_x, y: other_y } = Point { x: 10, y: 11 };

// you can ignore some fields
let Point { x: third_x, y: _ } = Point { x: 1, y: 2 };

// you can only take some fields and ignore the rest
let Point { x: fourth_x, .. } = Point { x: 3, y: 4 };
}

Irrefutable patterns are also available in function parameters and every place where refutable patterns are valid.

Refutable patterns only match in some cases, either because you are matching a field against a constant, or because you are matching on a type that has multiple variants.

These patterns are only valid in the following three structures:

  • if-let
  • while-let
  • match
#![allow(unused)]
fn main() {
let result = Ok(5);
let option = Some(5);

if let Ok(5) = result {
    // only runs if result is Ok(5)
}

if let Ok(number) = result {
    // only runs if result is Ok and binds
    // the contained value to the identifier `number`.
    // You can use any valid identifier
}

if let Some(_) = option {
    // only runs if option is Some,
    // but ignores contained value
    // okay for other Enums, but for Option use methods .is_some(), is_none()
    // for Result use .is_ok(), .is_err()
}

struct Point {
    x: isize,
    y: isize,
}

let point = Point { x: 5, y: 5 };

if let Point { 5, y } = point {
    // only runs if x is 5,
    // binding the other field to the name y
}
}