Express Alternatives with Enums and Match

RustBeginner
Practice Now

Introduction

A struct groups fields that always belong together. An enum models a value that can be one of several alternatives, and each alternative may carry different data. Rust's match expression then handles those alternatives explicitly.

You will complete a message enum, destructure coordinates from one variant, and extend the model with a new variant. The compiler will deliberately show why every possible variant must be covered before the message processor can run.

Define Data-Carrying Variants

In this step, you will define three alternative shapes for one Message type.

Enter the prepared project and open the source:

cd /home/labex/project/message-processor
nano src/main.rs

An enum declaration lists variants inside braces. Code constructs a variant with the enum name, ::, and the variant name. Different variants of the same enum may carry different kinds of data.

Replace the Step 1 comment with:

    Text(String),
    Move { x: i32, y: i32 },
    Stop,

Text(String) carries one unnamed value, a shape Rust calls a tuple-like variant. Move { x, y } carries named fields, so it is called a struct-like variant. Stop carries no extra data and is called a unit variant. Remembering “one unnamed value, named fields, or no data” matters more than memorizing the formal names immediately. Despite their different shapes, every constructed value has the single type Message.

Save with Ctrl+O, press Enter, and exit with Ctrl+X. Check and run the prepared processor:

cargo check
cargo run --quiet

The output should be:

Text: Maintenance at 9
Move received
Stop requested

The prepared match selects one arm for each variant. Every arm has the form pattern => behavior, and commas separate the short arms. The Text(text) pattern names the carried string. The Move arm also names x and y, then temporarily groups them as (x, y). Parentheses here create a two-value tuple used only as prepared scaffolding; tuples are not a learning objective in this Lab. The name _coordinates begins with _, telling Rust that leaving this temporary value unused is intentional. This keeps the first run warning-free. In the next step, you will replace that scaffold and use both coordinates in visible output.

Use Destructured Variant Data

In this step, you will change the Move match arm so the coordinates extracted by its pattern appear in the output.

Patterns can take apart the variant that they match. In a struct-like variant, writing the field names creates bindings that the arm's expression can use.

Open the source:

nano src/main.rs

Replace the complete Move arm with:

        Message::Move { x, y } => println!("Move to ({x}, {y})"),

When a Move message arrives, the pattern binds its stored fields to local names x and y. The print expression uses those names; no separate field access or cast is needed.

Save and exit, then run:

cargo run --quiet

The middle line should now be:

Move to (3, -2)

The negative y value proves that the arm used the data carried by the actual variant instead of printing fixed coordinates.

Extend an Exhaustive Match

In this step, you will add a Pause message, observe the compiler's exhaustiveness check, and then handle the new alternative.

A match must cover every possible value of its enum. This rule means that adding a variant identifies each match that needs a decision about the new case.

Open the file and add this variant immediately below Stop:

nano src/main.rs
    Pause(u32),

Save and exit, then check the program. Failure is expected:

cargo check

Find the stable part of the diagnostic:

error[E0004]: non-exhaustive patterns: `Message::Pause(_)` not covered

The compiler points to match message because the enum can now contain a Pause value, but no arm explains what to do with it.

Open the source again. Add this arm below the Stop arm:

        Message::Pause(seconds) => println!("Pause for {seconds} seconds"),

Then remove the leading // from the prepared process(Message::Pause(5)); line in main. The pattern gives the carried u32 value the local name seconds.

Save and exit, then check and run:

cargo check
cargo run --quiet

The complete output should be:

Text: Maintenance at 9
Move to (3, -2)
Stop requested
Pause for 5 seconds

The successful check proves the match is exhaustive again, and the fourth line proves the new arm destructured the Pause duration.

Summary

You defined unit, tuple-like, and struct-like enum variants; destructured carried data with match patterns; and used compiler error E0004 to extend a match exhaustively after adding a new alternative.