Skip to main content
Rust Programming
CHAPTER 13 Beginner

Enums and Pattern Matching

Updated: May 18, 2026
5 min read

# CHAPTER 13

Enums and Pattern Matching

1. Chapter Introduction

In C or Java, an Enum is just a list of numbered constants. In Rust, Enums are incredibly powerful. An Enum in Rust allows you to define a type by enumerating its possible variants, and crucially, *those variants can hold entirely different types of data*. Combined with Rust's match statement, Enums provide the safest and most robust way to handle state and eliminate the dreaded "Null Reference Exception" forever.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Define basic Enums.
  • Define Enums where variants hold embedded data.
  • Master the Option<T> enum (Rust's replacement for null).
  • Extract data from Enums using the match statement.
  • Use the concise if let syntax for single pattern matching.

3. Basic Enums

An Enum allows you to say a value can only be one of a few things. For example, an IP address can either be V4 or V6.
rust
123456789
enum IpAddrKind {
    V4,
    V6,
}

fn main() {
    let four = IpAddrKind::V4;
    let six = IpAddrKind::V6;
}

4. Enums with Embedded Data (The Rust Superpower)

What if we want to store the actual IP address data *inside* the enum? We don't need a separate Struct! Rust enums can hold data directly.
rust
123456789
enum IpAddr {
    V4(u8, u8, u8, u8), // Holds four integers
    V6(String),         // Holds a String
}

fn main() {
    let home = IpAddr::V4(127, 0, 0, 1);
    let loopback = IpAddr::V6(String::from("::1"));
}

*Notice how V4 holds a tuple of integers, and V6 holds a String. This flexibility is impossible in most languages.*

5. The Option Enum (Goodbye null!)

Tony Hoare, the inventor of the null reference, calls it his "Billion Dollar Mistake" because it causes so many system crashes. Rust does not have null. Instead, if a value might be absent, Rust forces you to use the built-in Option enum.
rust
12345
// This is how Option is defined in the standard library:
enum Option<T> { // <T> means it can hold any type of data
    None,
    Some(T),
}

If a variable is an Option, the compiler *forces* you to check if it is None before you are allowed to use the data inside Some.

rust
123456
fn main() {
    let some_number = Some(5);
    let absent_number: Option<i32> = None;

    // let total = 5 + some_number; // ERROR! You cannot add an i32 and an Option<i32>
}

6. Extracting Data with match

How do we get the 5 out of the Some(5)? We use the exhaustive match statement!
rust
123456789101112
fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        None => None, // If it's missing, return missing
        Some(i) => Some(i + 1), // If it has data (i), add 1 to it and wrap it back in Some
    }
}

fn main() {
    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);
}

*Because match is exhaustive, you cannot accidentally forget to handle the None case. Null pointer exceptions are mathematically impossible!*

7. The if let Syntax

Sometimes, match is too verbose if you only care about ONE specific variant and want to ignore the rest. You can use if let as syntactic sugar.
rust
1234567891011121314
fn main() {
    let config_max = Some(3u8);

    // Using match:
    match config_max {
        Some(max) => println!("The maximum is configured to be {}", max),
        _ => (), // Do nothing for None
    }

    // Using if let (Shorter, cleaner!):
    if let Some(max) = config_max {
        println!("The maximum is configured to be {}", max);
    }
}

8. Common Mistakes

  • Assuming Option<T> is the same as T: Trying to use Some(5) as if it were just 5. The compiler treats them as completely different types. You must unpack it using match or unwrap() (which we will learn in Chapter 15).
  • Forgetting Variants: When using a match on an Enum, forgetting to list one of the variants. The compiler will aggressively refuse to compile until every variant is handled.

9. Best Practices

  • Use Enums for State Machines: Enums are perfect for modeling states. For example, a WebConnection enum could be Disconnected, Connecting, or Connected(SocketData). The compiler guarantees you can only access the SocketData if the state is actually Connected.

10. Exercises

  1. 1. Define an Enum called Message with variants: Quit, Move { x: i32, y: i32 }, and Write(String).
  1. 2. Create a function processmessage(msg: Message) that uses a match statement to print a different phrase depending on which message was passed.

11. MCQs with Answers

Question 1

How are Rust Enums different from C or Java Enums?

Q2. Does Rust have a null keyword? a) Yes b) No, it uses the Option Enum to represent the concept of an absent value safely Answer: b) No, it uses the Option Enum.
Question 3

What are the two variants of the Option<T> Enum?

Q4. Can you mathematically add an i32 and an Option<i32> together directly? a) Yes b) No, they are different types. The compiler forces you to handle the Option first. Answer: b) No.
Question 5

What control flow construct is most commonly used to extract data from an Enum?

Question 6

What happens if you write a match statement for an Enum but forget one of the variants?

Question 7

If you only care about matching ONE specific variant and want to ignore the rest, what syntax provides a cleaner alternative to match?

Question 8

What does if let Some(x) = myval do?

Q9. Can Enums have impl blocks to define methods just like Structs? a) Yes b) No Answer: a) Yes.

Q10. Why is the Option pattern considered the ultimate solution to the "Billion Dollar Mistake"? a) Because it's faster b) Because the compiler mathematically proves at compile-time that you have checked for the absence of data before using it, making null pointer crashes impossible. Answer: b) Because it forces compile-time checking for data absence.

12. Interview Questions

  • Q: Describe how Rust eliminates the Null Pointer Exception using the type system.
  • Q: Explain the syntax and use case for if let. Provide an example.

13. Summary

Enums and Pattern Matching represent the peak of Rust's expressive type system. By embedding data directly into variants and forcing exhaustive checking via match, developers can encode complex business logic and state machines perfectly. Furthermore, the Option enum permanently solves the null reference problem that has plagued software engineering for decades.

14. Next Chapter Recommendation

We have mastered basic types, structs, and enums. Now we need to look at how Rust handles massive amounts of data. In Chapter 14: Collections in Rust, we will explore Vectors, Strings, and HashMaps, and understand how they manage memory on the Heap.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·