03open 25 min

Enums and pattern matching: explicit state instead of ad hoc shape

Model variant-rich data directly with enums and handle it exhaustively with match expressions.

by the end of this lesson you can

  • Models the variant as an enum rather than a string tag
  • Uses match instead of string comparisons
  • Makes data carried by each variant explicit

Overview

Python developers often model state with classes, dictionaries, or string tags. Rust gives you enums and pattern matching, which make legal states and required handling visible in the type system.

In Python, you often

represent variants with dictionaries, classes, or stringly-typed flags and trust conventions to keep cases aligned.

In Rust, the common pattern is

to express variants directly as enum cases and use match to handle them exhaustively.

why this difference matters

This reduces impossible states and shifts branching logic from convention into the compiler's field of view.

Python

status = {"kind": "ok", "value": 42}
if status["kind"] == "ok":
    print(status["value"])

Rust

enum Status {
    Ok(i32),
    Missing,
}

match status {
    Status::Ok(value) => println!("{}", value),
    Status::Missing => println!("missing"),
}

Deeper comparison

Python version

event = {"type": "click", "x": 10, "y": 20}

if event["type"] == "click":
    handle_click(event["x"], event["y"])

Rust version

enum Event {
    Click { x: i32, y: i32 },
    KeyPress(char),
}

match event {
    Event::Click { x, y } => handle_click(x, y),
    Event::KeyPress(key) => handle_key(key),
}

Reflect

What gets clearer when valid states are represented explicitly as enum variants instead of conventions in data structures?

what a strong answer notices

A strong answer mentions exhaustive handling, impossible-state reduction, and clearer branching logic at the use site.

Rewrite

Rewrite this Python tagged-data example into a Rust enum plus match expression.

Rewrite this Python

response = {"kind": "error", "message": "timeout"}

what good looks like

  • Models the variant as an enum rather than a string tag
  • Uses match instead of string comparisons
  • Makes data carried by each variant explicit

Practice

Design a Rust enum for a background job that can be queued, running, completed, or failed with an error message.

success criteria

  • Represents state transitions as explicit variants
  • Uses carried data only where needed
  • Shows how pattern matching would read that state safely

Common mistakes

  • Recreating tagged dictionaries instead of using enums.
  • Using strings to represent cases the type system could encode directly.
  • Treating match as a verbose if/else rather than a modeling tool.

takeaways

  • This reduces impossible states and shifts branching logic from convention into the compiler's field of view.
  • A strong answer mentions exhaustive handling, impossible-state reduction, and clearer branching logic at the use site.
  • Represents state transitions as explicit variants