Basic

Conditionals and Matching

Make decisions with if and the powerful match expression.

What you will see

positive

About 2 min of reading

Quick check

Before this new lesson, one small question about the lesson you just finished. Recall it, do not look it up.

Try It

You will branch with if/else, turn if into a value expression, and match on values with the match expression.

1

I branch on a score. The first matching arm prints, so a score of 85 prints B.

fn main() { let score = 85; if score >= 90 { println!("A"); } else if score >= 80 { println!("B"); } else { println!("C"); } }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
B
2

I make if an expression that assigns a value. The matching branch value flows into the variable.

fn main() { let score = 95; let grade = if score >= 90 { "A" } else { "C" }; println!("{}", grade); }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
A
3

I match on a day value. The arm 2 | 3 matches, so it prints early.

fn main() { let day = 3; match day { 1 => println!("Mon"), 2 | 3 => println!("early"), _ => println!("other"), } }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
early
4

I match on a value with no matching arm. The catch-all _ arm runs for anything unlisted.

fn main() { let day = 5; match day { 1 => println!("Mon"), 2 | 3 => println!("early"), _ => println!("other"), } }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
other
5

I add a guard to a match arm. The x if x > 0 arm runs for positive values.

fn main() { let n = 4; match n { x if x > 0 => println!("positive"), x if x < 0 => println!("negative"), _ => println!("zero"), } }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
positive

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

A value is compared against patterns; the matching arm runs and returns.
1 Evaluate the matched value
↓
2 Compare against each pattern
↓
3 Run the first matching arm
↓
4 Return the arm's value
Why this works
Exhaustive matching

match must handle every possible value:

match color {
    Red => {},
    Green => {},
    Blue => {},
}

If you forget a case, the compiler errors. Use _ to catch anything unlisted. This guarantees no value slips through unhandled.

Match guards

Add conditions to match arms:

match n {
    x if x > 0 => println!("positive"),
    x if x < 0 => println!("negative"),
    _ => println!("zero"),
}

The if after the pattern is a guard. Only arms whose guard is true run, letting you add logic to patterns.

Examples

Basic if/else

Branching on a condition

let score = 85;
if score >= 90 {
    println!("A");
} else if score >= 80 {
    println!("B");
} else {
    println!("C");
}

Rust if blocks are expressions, they can produce a value:

let grade = if score >= 90 { "A" } else { "C" };

Why it works: the branches must return the same type.

match expressions

Pattern matching

let day = 3;
match day {
    1 => println!("Mon"),
    2 | 3 => println!("early"),
    _ => println!("other"),
}

match compares a value against patterns. _ is a catch-all. Rust requires match to be **exhaustive*: every case covered.

Why it works: match is an expression that returns a value.

if let syntax

Concise matching

let Some(x) = optional;
if let Some(x) = optional {
    println!("got {x}");
}

if let combines an if and a match for the common case of handling one variant. It keeps code short when you only care about one outcome.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Primitive Types
Previous Lesson
Primitive Types
Next Lesson
Loops
Loops →