Defining Enums
An enum (short for enumeration, also called a sum type or tagged union in type theory) defines a custom data type by listing all of its possible variants. Whereas a struct groups multiple fields together so an instance holds all of them at once (an "AND" type), an enum represents a value that can be exactly one of several possible alternatives at any given moment (an "OR" type).
Struct ("AND" Product Type) vs Enum ("OR" Sum Type)
Struct (Product Type — holds ALL fields simultaneously):
struct HttpResponse {
status: u16, AND
body: String,
}
Enum (Sum Type — holds EXACTLY ONE variant at a time):
enum NetworkEvent {
Connected, OR
Message(String), OR
Disconnected { code: u16, reason: String },
}
Declaring and Instantiating an Enum
An enum is declared with the enum keyword followed by its name in UpperCamelCase and a brace-enclosed list of variants (also in UpperCamelCase). Variants are accessed using the namespace path operator :: (EnumName::VariantName):
#[derive(Debug, PartialEq)]
enum TrafficLight {
Red,
Yellow,
Green,
}
fn wait_time_seconds(light: &TrafficLight) -> u32 {
match light {
TrafficLight::Red => 45,
TrafficLight::Yellow => 5,
TrafficLight::Green => 0,
}
}
fn main() {
let current = TrafficLight::Red;
let next = TrafficLight::Green;
println!("Current light: {current:?} (wait {}s)", wait_time_seconds(¤t));
println!("Same state? {}", current == next);
}
Current light: Red (wait 45s)
Same state? false
Notice that all variants (TrafficLight::Red, TrafficLight::Yellow, TrafficLight::Green) have the exact same type: TrafficLight. A function accepting TrafficLight can receive any of its variants.
Mixing Variant Shapes in a Single Enum
Unlike C, C++, or Java enums—where variants are merely named integer constants—each variant of a Rust enum can optionally carry its own associated data of any type and shape:
| Variant Kind | Syntax Inside enum |
Mirrors Which struct Form? |
Construction Syntax |
|---|---|---|---|
| Unit variant | Quit, |
Unit-like struct (struct Quit;) |
Command::Quit |
| Tuple variant | Write(String), or Move(i32, i32), |
Tuple struct (struct Write(String);) |
Command::Write(text) |
| Struct variant | Resize { width: u32, height: u32 }, |
Named-field struct (struct Resize { ... }) |
Command::Resize { width: 800, height: 600 } |
#[derive(Debug)]
enum Command {
Quit, // Unit variant (no payload)
Echo(String), // Tuple variant (1 field)
MoveTo(i32, i32), // Tuple variant (2 fields)
Resize { width: u32, height: u32 }, // Struct variant (named fields)
}
fn main() {
let queue = [
Command::MoveTo(10, -20),
Command::Resize { width: 1920, height: 1080 },
Command::Echo(String::from("Hello, enums!")),
Command::Quit,
];
for cmd in &queue {
println!("Queued command: {cmd:?}");
}
}
Queued command: MoveTo(10, -20)
Queued command: Resize { width: 1920, height: 1080 }
Queued command: Echo("Hello, enums!")
Queued command: Quit
Defining Methods on Enums (impl)
Just like structs, enums can have methods and associated functions defined on them inside an impl block:
#[derive(Debug)]
enum PaymentMethod {
Cash,
Card { last_four: u16 },
Voucher(u64),
}
impl PaymentMethod {
fn summary(&self) -> String {
match self {
Self::Cash => String::from("Paid in cash"),
Self::Card { last_four } => format!("Paid with card ending in {last_four:04}"),
Self::Voucher(code) => format!("Redeemed voucher #{code}"),
}
}
}
fn main() {
let payment = PaymentMethod::Card { last_four: 42 };
println!("{}", payment.summary());
}
Paid with card ending in 0042
Inside impl PaymentMethod, Self::Cash is a convenient shorthand for PaymentMethod::Cash.
Bringing Enum Variants into Scope with use
If you match or construct an enum's variants repeatedly inside a function or module, you can bring its variants directly into local scope with use EnumName::*; (just as the standard prelude automatically imports Option::Some, Option::None, Result::Ok, and Result::Err):
#[derive(Debug)]
enum LogLevel {
Info,
Warn,
Error,
}
fn main() {
use LogLevel::*;
let level = Warn; // Written directly without `LogLevel::` prefix
println!("Active log level: {level:?}");
}
Active log level: Warn