ProgrammingRust Developer (Infrastructure/Core Libraries)

How does the match operator work in Rust: features of exhaustiveness checking, pattern guards, and nested pattern matching?

Pass interviews with Hintsage AI assistant

Answer.

Background

The match operator in Rust is a powerful pattern matching tool borrowed from functional languages. Unlike equivalents in C/C++, Rust enforces strict exhaustiveness checking, and every possible variant must have a branch.

Problem

Errors when working with match are often related to incorrectly accounting for all type variants (for example, enums), improper handling of guards (conditions on branches), or complex nested structures. Incorrect handling leads to compile-time errors or implicitly wrong logic.

Solution

  • Exhaustiveness checking does not allow skipping any variant, and the compiler will require adding a branch for each of them (or a catch-all _).
  • Pattern guards supplement match branches with additional conditions (if after the pattern).
  • Nested matching allows unpacking complex, nested enums or tuples in a single match construct.

Example code:

enum Shape { Circle(f64), Rectangle { width: f64, height: f64 }, } fn print_area(s: Shape) { match s { Shape::Circle(r) if r > 0.0 => println!("area = {}", 3.14 * r * r), Shape::Rectangle { width, height } if width > 0.0 && height > 0.0 => println!("area = {}", width * height), _ => println!("invalid shape"), } }

Key features:

  • Full pattern matching check
  • Ability to use guard expressions for filtering
  • Matching with nested structures and working with destructuring

Trick questions.

Does the order of branches in match affect execution?

Yes, the order of branches is important: as soon as the first match is found, subsequent ones are not checked. This is especially critical with pattern guards — if there is an earlier branch with a guard, it will intercept the value before the catch-all.

Is catch-all (_) mandatory in match for enums?

No, if you have explicitly covered all cases (and the type declarations themselves will not change over time). However, catch-all is needed when working with types that may have additional values or when you do not want to explicitly handle all branches.

Can multiple patterns (alternatives) be used in a single match branch?

Yes. You can combine patterns using a vertical bar (|):

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

Common mistakes and anti-patterns

  • Forgetting to handle all enum variants without a catch-all
  • Using catch-all _ too early (before specific branches)
  • Ignoring the order of branches with guards

Real-life examples

Negative case

A developer wrote a match with a catch-all at the beginning and could not correctly handle specific cases.

Pros:

The program compiles.

Cons:

The specific logic never works, part of the code is not covered.

Positive case

Explicit handling of all enum variants, catch-all only as the last branch, separate guards for atypical cases.

Pros:

Predictability, the compiler helps not to forget a variant, easy to extend types.

Cons:

Additional boilerplate code when there are many variants.