Patterns

Simple

A pattern in its most simple form:


#![allow(unused)]
fn main() {
let x = 5;
}

let PATTERN = EXPRESSION;

Destructure Pattern


#![allow(unused)]
fn main() {
let (x, y, z) = (1, 2, 3);
}

Ignore Pattern


#![allow(unused)]
fn main() {
let (x, ..) = (1, 2, 3);
// OR
let (x, _, _) = (1, 2, 3);
}

Destructure Struct

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

fn main() {
    let p = Point { x: 0, y: 7 };

    let Point { x, y } = p;
    assert_eq!(0, x);
    assert_eq!(7, y);
}

You could change the variable names like this:


#![allow(unused)]
fn main() {
let Point { x: a, y: b } = p;

println("{} {}", a, b);
}

Function pattern

Here &(x, y): &(i32, i32) is the pattern

fn print_coordinates(&(x, y): &(i32, i32)) {
    println!("Current location: ({}, {})", x, y);
}

fn main() {
    let point = (3, 5);
    print_coordinates(&point);
}

Match values

With an or statement


#![allow(unused)]
fn main() {
let x = 1;

match x {
	1 | 2 => println!("one or two"),
	3 => println!("three"),
	_ => println!("anything"),
}
}

With a range


#![allow(unused)]
fn main() {
let x = 5;

match x {
	1..=5 => println!("one through five"),
	_ => println!("something else"),
}
}

Match with a destructured struct

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

impl Point {
    fn where_am_i(&self) {
        match self {
            Point { x, y: 0 } => println!("On the x axis at {}", x),
            Point { x: 0, y } => println!("On the y axis at {}", y),
            Point { x, y } => println!("On neither axis: ({}, {})", x, y),
        }
    }
}

fn main() {
    let p = Point { x: 8, y: 0 };
    p.where_am_i();

    let p = Point { x: 0, y: 7 };
    p.where_am_i();

    let p = Point { x: 8, y: 7 };
    p.where_am_i();
}

Destructure a struct inside an enum

enum Message {
    Move { x: i32, y: i32 },
    ChangeColor(i32, i32, i32),
}

impl Message {
    fn print_me(&self) {
        match self {
            Message::Move { x, y } => {
                println!("Move in the x direction {} and in the y direction {}", x, y);
            }
            Message::ChangeColor(r, g, b) => {
                println!("Change the color to red {}, green {}, and blue {}", r, g, b)
            }
        }
    }
}

fn main() {
    let msg = Message::Move { x: 10, y: 15 };
    msg.print_me();

    let msg = Message::ChangeColor(0, 160, 255);
    msg.print_me();
}

Nested enum pattern matching

use Color::Hsv;
use Color::Rgb;
use Message::ChangeColor;
enum Color {
    Rgb(i32, i32, i32),
    Hsv(i32, i32, i32),
}

enum Message {
    ChangeColor(Color),
}

impl Message {
    fn print_me(&self) {
        match self {
            ChangeColor(Rgb(r, g, b)) => {
                println!("Change the color to red {}, green {}, and blue {}", r, g, b)
            }
            ChangeColor(Hsv(r, g, b)) => {
                println!( "Change the color to hue {}, saturation {}, and value {}", r, g, b)
            }
        }
    }
}

fn main() {
    let msg = ChangeColor(Rgb(25, 50, 50));
    msg.print_me();
    let msg = ChangeColor(Hsv(50, 45, 180));
    msg.print_me();
}

Ignoring

Underscore

Use the underscore to ignore certain patterns


#![allow(unused)]
fn main() {
let numbers = (2, 4, 8, 16, 32);

match numbers {
    (first, _, third, _, fifth) => {
        println!("Some numbers: {}, {}, {}", first, third, fifth)
    }
}
}

..

Use just the x value from a Point:


#![allow(unused)]
fn main() {
struct Point {
    x: i32,
    y: i32,
    z: i32,
}

let origin = Point { x: 0, y: 0, z: 0 };

match origin {
    Point { x, .. } => println!("x is {}", x),
}
}

Match guards

Adds an extra check to an arm


#![allow(unused)]
fn main() {
let num = Some(4);

match num {
    Some(x) if x < 5 => println!("less than five: {}", x),
    Some(x) => println!("{}", x),
    None => (),
}
}

Check if the value of x matches 4 | 5 | 6, but y being true takes precedence:


#![allow(unused)]
fn main() {
let x = 4;
let y = false;

match x {
    4 | 5 | 6 if y => println!("yes"),
    _ => println!("no"),
}
}

Match Binding

@ gives access to variable which has been matched

enum Message {
    Hello { id: i32 },
}

fn main() {
    let msg = Message::Hello { id: 5 };

    match msg {
        Message::Hello {
            id: id_variable @ 3..=7,
        } => println!("Found an id in range: {}", id_variable),
        Message::Hello { id: 10..=12 } => {
            println!("Found an id in another range")
        }
        Message::Hello { id } => println!("Found some other id: {}", id),
    }
}

Complex destructure

Making all values available through a destructure:


#![allow(unused)]
fn main() {
let ((feet, inches), Point { x, y }) = ((3, 10), Point { x: 3, y: -10 });
}