Menu
Coddy logo textTech

Matching Data Variants

Part of the Object Oriented Programming section of Coddy's Rust journey — lesson 16 of 61.

In the previous lesson, you used match inside enum methods to handle different variants. Now let's focus on how match actually extracts the data stored inside those variants—a technique called destructuring.

When you match on an enum variant that holds data, you can bind that data to variables right in the pattern:

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

fn handle_event(event: Event) {
    match event {
        Event::Click { x, y } => {
            println!("Clicked at ({}, {})", x, y);
        }
        Event::KeyPress(key) => {
            println!("Key pressed: {}", key);
        }
        Event::Resize(width, height) => {
            println!("Resized to {}x{}", width, height);
        }
    }
}

Each arm extracts data differently based on the variant's structure. For struct-like variants, you use { field_name } to pull out named fields. For tuple variants, you use positional variables like (width, height).

The variable names you choose become available inside that match arm. This is powerful because you're simultaneously checking which variant you have and gaining access to its payload.

The compiler ensures you handle every variant, and the extracted values are ready to use immediately—no extra steps needed.

challenge icon

Challenge

Easy

Let's build a command processor that handles different types of user commands. Each command carries different data, and your processor will use pattern matching to extract that data and produce appropriate responses.

You'll create two files to organize your code:

  • command.rs: Define a public Command enum with three variants:
    • Say — holds a single String message (tuple syntax)
    • Move — holds named fields: direction (String) and steps (u32)
    • Calculate — holds two i32 values representing numbers to add (tuple syntax)
    Then implement an execute method that uses match to destructure each variant and return a String describing the action taken.
  • main.rs: Bring in your command module, create one instance of each command variant using the provided inputs, and call the execute method on each to print the results.

Your execute method should destructure each variant to access its data and return messages in these exact formats:

  • For Say: Saying: {message}
  • For Move: Moving {steps} steps {direction}
  • For Calculate: {a} + {b} = {sum}

Your output should display the result of each command on its own line:

Saying: {message}
Moving {steps} steps {direction}
{a} + {b} = {sum}

For example, with a say message of "Hello world", a move of 5 steps "north", and a calculation of 10 and 25, the output would be:

Saying: Hello world
Moving 5 steps north
10 + 25 = 35

You will receive five inputs: the say message, the direction, the number of steps, and the two numbers to calculate.

Cheat sheet

Pattern matching with match allows you to destructure enum variants and extract their data directly in the pattern.

For tuple variants, use positional variables:

enum Event {
    KeyPress(char),
    Resize(u32, u32),
}

match event {
    Event::KeyPress(key) => {
        println!("Key: {}", key);
    }
    Event::Resize(width, height) => {
        println!("{}x{}", width, height);
    }
}

For struct-like variants, use named field syntax:

enum Event {
    Click { x: i32, y: i32 },
}

match event {
    Event::Click { x, y } => {
        println!("Clicked at ({}, {})", x, y);
    }
}

The extracted variables become available within their respective match arm, allowing you to check the variant type and access its data simultaneously.

Try it yourself

mod command;

use command::Command;

fn main() {
    // Read inputs
    let mut say_message = String::new();
    std::io::stdin().read_line(&mut say_message).expect("Failed to read line");
    let say_message = say_message.trim().to_string();

    let mut direction = String::new();
    std::io::stdin().read_line(&mut direction).expect("Failed to read line");
    let direction = direction.trim().to_string();

    let mut steps_input = String::new();
    std::io::stdin().read_line(&mut steps_input).expect("Failed to read line");
    let steps: u32 = steps_input.trim().parse().expect("Failed to parse steps");

    let mut num1_input = String::new();
    std::io::stdin().read_line(&mut num1_input).expect("Failed to read line");
    let num1: i32 = num1_input.trim().parse().expect("Failed to parse num1");

    let mut num2_input = String::new();
    std::io::stdin().read_line(&mut num2_input).expect("Failed to read line");
    let num2: i32 = num2_input.trim().parse().expect("Failed to parse num2");

    // TODO: Create a Say command using say_message and execute it
    
    // TODO: Create a Move command using direction and steps, and execute it
    
    // TODO: Create a Calculate command using num1 and num2, and execute it
    
    // TODO: Print the results of each command execution
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming