Enums & Pattern Matching
Rust is a systems programming language focused on speed, memory safety, and fearless concurrency — and enums let you model a value that is exactly one of several possibilities, which pattern matching then handles exhaustively.
Learn Enums & Pattern Matching in our free Rust course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Rust course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll define enums (including variants that carry data), match on them, destructure their contents, and use the concise if let .
What You'll Learn in This Lesson
1️⃣ Defining Enums and Matching
An enum defines a type by listing its possible variants . You then inspect a value with match , which compares it against patterns. A match is an expression (it returns a value) and must be exhaustive — every variant must be handled.
If you deleted one arm, the compiler would refuse to build and tell you exactly which variant you forgot. That guarantee is one of Rust's most loved features.
2️⃣ Variants with Data and if let
The real power of enums is that each variant can carry data — tuple-style like Circle(f64) or struct-style with named fields. A match can then destructure that data into variables. When you only care about one variant, if let is a tidy shortcut.
Notice how each match arm pulled the values out: Circle(r) binds the radius to r , and the triangle arm binds its named fields. The if let handled just the circle case without a full match.
Your turn. Fill in the blanks marked ___ , then run it.
Model a traffic light as an enum and write functions that transition and describe it. Run it with cargo run .
📋 Quick Reference — Enums & match
Practice quiz
What does an enum define in Rust?
- A list of functions
- A collection of fields
- A type that is exactly one of several variants
- A trait
Answer: A type that is exactly one of several variants. An enum lists the possible variants a value can be; a value is exactly one of them at a time.
How are Rust enums more powerful than enums in many other languages?
- Each variant can carry its own data
- They are always integers
- They cannot be matched
- They allow null
Answer: Each variant can carry its own data. Rust enum variants can hold data, and different variants can carry different kinds and amounts of data.
What does it mean that a match must be exhaustive?
- It must have exactly two arms
- It must use a loop
- It can only match integers
- Every possible variant must be handled or the code won't compile
Answer: Every possible variant must be handled or the code won't compile. Rust requires every variant be covered so you can never silently forget a case.
What does the _ arm in a match do?
- Matches nothing
- Acts as a wildcard catch-all for anything not already covered
- Repeats the previous arm
- Causes a panic
Answer: Acts as a wildcard catch-all for anything not already covered. _ is a wildcard that matches any case not handled by earlier arms, serving as a default.
When is if let preferable to a full match?
- When you care about only one pattern and ignore the rest
- When handling many variants
- When you need exhaustiveness
- Never
Answer: When you care about only one pattern and ignore the rest. if let is concise for a single pattern, avoiding a match with one arm plus a _ catch-all.
Given the Coin enum where Nickel is 5 and Dime is 10, what total do coins [Dime, Quarter, Penny] sum to in cents?
- 16
- 40
- 36
- 25
Answer: 36. 10 (Dime) + 25 (Quarter) + 1 (Penny) = 36 cents.
How can a match arm extract data out of a variant like Circle(f64)?
- By indexing it
- By destructuring, e.g. Shape::Circle(r) binds r
- It can't
- By calling .get()
Answer: By destructuring, e.g. Shape::Circle(r) binds r. match arms destructure variants: Shape::Circle(r) binds the radius to r.
For Shape::Rectangle(w, h) with area w * h, what is the area of Rectangle(3.0, 4.0)?
- 7.00
- 6.00
- 34.00
- 12.00
Answer: 12.00. w * h = 3.0 * 4.0 = 12.00.
What must be true of every arm of a match used as a value?
- They must return different types
- They must return the same type
- They must each panic
- They must be empty
Answer: They must return the same type. A match is an expression, so all arms must evaluate to the same type.
What is the downside of using a _ catch-all arm?
- It is slower
- It can't compile
- It silently absorbs new variants you add later
- It only matches numbers
Answer: It silently absorbs new variants you add later. Because _ swallows everything else, it hides new variants instead of forcing you to handle them.