An enum in Rust is a type that can represent one of several possible variants, each optionally holding different types of data. Enums are ideal for modeling choices, states, or patterns like Option, Result, and more.
If structs in Rust let you group fields together, enums let you define a type that can be only one of several named possibilities. This is Rust’s way of expressing things like “a value is either this or that.”
In this post, I will show you how to define enums, use them in pattern matching, and combine them with data. Enums are central to how Rust handles options, errors, and logic branches safely.
What is an Enum?
An enum lets you define a type by listing its possible variants.
Example
enum Direction {
Up,
Down,
Left,
Right,
}
This means a value of type Direction can be Up, Down, Left, or Right, but never more than one at the same time.
Creating and Using Enums
To use an enum, create a value with one of its variants:
let dir = Direction::Left;
You refer to a variant using :: syntax.
Pattern Matching with Enums
You usually match on enums using match:
match dir {
Direction::Up => println!("Going up"),
Direction::Down => println!("Going down"),
Direction::Left => println!("Turning left"),
Direction::Right => println!("Turning right"),
}
Rust forces you to handle every possible case, which makes enum usage safe and predictable.
Enums with Data
Variants can also hold data:
enum Message {
Quit,
Move { x: i32, y: i32 },
Text(String),
ChangeColor(u8, u8, u8),
}
Each variant has its own structure:
let m1 = Message::Quit;
let m2 = Message::Move { x: 10, y: 20 };
let m3 = Message::Text(String::from("Hello"));
let m4 = Message::ChangeColor(255, 255, 0);
This is more flexible than a struct because each variant can store different kinds of values.
Matching Enums with Data
Use match to destructure the values:
match m2 {
Message::Move { x, y } => println!("Move to {}, {}", x, y),
Message::Quit => println!("Quit"),
Message::Text(s) => println!("Message: {}", s),
Message::ChangeColor(r, g, b) => println!("RGB: {}, {}, {}", r, g, b),
}
This works just like match on basic enums, but with structured data.
Enum Methods
Just like structs, enums can have methods in an impl block:
impl Message {
fn call(&self) {
match self {
Message::Quit => println!("Goodbye"),
Message::Text(s) => println!("Text: {}", s),
_ => println!("Other message"),
}
}
}
You can then call:
let msg = Message::Text(String::from("Hi"));
msg.call();
Enums in the Standard Library
Rust uses enums all over the place. Two of the most important are:
- Option – for values that may or may not exist
- Result – for operations that may fail
You will learn more about these in upcoming lessons.
Summary
Enums let you define a type that can take on multiple structured forms. You use them with match to handle all possible cases safely. They are powerful, readable, and core to idiomatic Rust.
Rust Learning Path
- Introduction to Rust
- Setting Up Rust Development Environment
- Your First Rust Program
- Variables and Mutability in Rust
- Constants and Immutability in Rust
- Type Annotations and Inference in Rust
- Variable Shadowing and Scope in Rust
- Rust Primitive Data Types
- Working with Strings in Rust
- Every Operator in Rust Explained
- Tuples in Rust
- Arrays and Slices in Rust
- Rust Decision Making: if & match
- Loops in Rust
- Reading Input from the Console in Rust
- Mastering Rust Functions (For Beginners)
- Understanding Ownership in Rust
- Borrowing and References in Rust
- Copy Types vs. Move Semantics in Rust
- Cloning Data in Rust
- Methods and Associated Functions in Rust
- Enums: Defining Variant Types in Rust
- Pattern Matching with Enums in Rust
- The Option Type: Null Safety in Rust
- Error Handling with Result
- Unrecoverable Errors in Rust
- Organizing Code with Modules in Rust
- Cargo Basics: Rust Package Manager
- How to Use External Crates in Rust