Enum Variants
Each possible case listed inside an enum definition is called a variant. In Rust, an enum's variants live under the enum's namespace (Enum::Variant), all construct values of that same Enum type, and can take any of three structural shapes: unit variants, tuple variants, or struct variants.
The Three Variant Shapes Compared
enum WebEvent {
PageLoad, <-- 1. Unit Variant (no associated data)
KeyPress(char), <-- 2. Tuple Variant (positional fields in `(...)`)
Click { x: i64, y: i64 }, <-- 3. Struct Variant (named fields in `{ ... }`)
}
| Variant Shape | Declaration Syntax | Construction Syntax | Pattern-Matching Syntax |
|---|---|---|---|
| Unit Variant | PageLoad, |
WebEvent::PageLoad |
WebEvent::PageLoad => ... |
| Tuple Variant | KeyPress(char), |
WebEvent::KeyPress('q') |
WebEvent::KeyPress(ch) => ... |
| Struct Variant | Click { x: i64, y: i64 }, |
WebEvent::Click { x: 10, y: 20 } |
WebEvent::Click { x, y } => ... |
enum WebEvent {
PageLoad,
KeyPress(char),
Paste(String),
Click { x: i64, y: i64 },
}
fn inspect_event(event: &WebEvent) {
match event {
WebEvent::PageLoad => println!("Page loaded"),
WebEvent::KeyPress(c) => println!("Key pressed: '{c}'"),
WebEvent::Paste(text) => println!("Pasted text ({} bytes): \"{text}\"", text.len()),
WebEvent::Click { x, y } => println!("Mouse clicked at ({x}, {y})"),
}
}
fn main() {
let events = [
WebEvent::PageLoad,
WebEvent::KeyPress('R'),
WebEvent::Paste(String::from("cargo run")),
WebEvent::Click { x: 320, y: 240 },
];
for ev in &events {
inspect_event(ev);
}
}
Page loaded
Key pressed: 'R'
Pasted text (9 bytes): "cargo run"
Mouse clicked at (320, 240)
Variants Are Values of the Enum Type—Not Separate Types!
A key rule in Rust's type system is that an enum variant is not a standalone type. You cannot declare a variable or function parameter whose type is Option::Some or WebEvent::Click; the type is always the parent enum (Option<T> or WebEvent):
// ❌ does not compile
enum Status {
Active(u32),
Inactive,
}
fn process_active(s: Status::Active) {}
fn main() {}
error[E0573]: expected type, found variant `Status::Active`
--> src/main.rs:6:22
|
6 | fn process_active(s: Status::Active) {}
| ^^^^^^^^^^^^^^ not a type
|
help: you might have meant to use theiana enum type
|
6 | fn process_active(s: Status) {}
| ~~~~~~
error: aborting due to 1 previous error
If a function genuinely requires only the data of a single variant, pass that inner payload type directly (fn process_active(id: u32)) or wrap the payload in its own standalone struct (struct ActiveState(u32);) and store that struct inside the enum variant (Active(ActiveState)).
Tuple Variants as Constructor Functions
When you declare a tuple variant like KeyPress(char) or Some(T), the compiler automatically generates a constructor function with the signature fn(char) -> WebEvent (or fn(T) -> Option<T>).
This lets you pass a tuple variant name directly to higher-order iterator methods like .map():
#[derive(Debug)]
enum Measurement {
Celsius(f64),
}
fn main() {
let raw_readings = [0.0, 21.5, 100.0];
// Pass `Measurement::Celsius` directly as a `fn(f64) -> Measurement` function!
let tagged: [Measurement; 3] = raw_readings.map(Measurement::Celsius);
println!("Tagged readings: {tagged:?}");
}
Tagged readings: [Celsius(0.0), Celsius(21.5), Celsius(100.0)]
Explicit Discriminant Values
Under the hood, each variant of an enum is identified at runtime by an integer tag called its discriminant (0, 1, 2, ... by default). For enums with unit variants (or enums annotated with a primitive representation like #[repr(u8)]), you can assign explicit integer discriminants to variants using =:
#[repr(u16)]
#[derive(Debug, Clone, Copy)]
enum HttpStatus {
Ok = 200,
Created = 201,
NotFound = 404,
InternalServerError = 500,
}
fn main() {
let status = HttpStatus::NotFound;
// Cast a fieldless enum directly to its integer discriminant with `as`:
let code: u16 = status as u16;
println!("{status:?} has numeric code {code}");
}
NotFound has numeric code 404
Public Enum Visibility Rule (pub enum)
Unlike a struct—where marking pub struct Foo keeps its fields private by default—marking an enum pub enum Bar automatically makes all of its variants and their fields public! Why? Because an enum's purpose is to be constructed and pattern-matched across all of its variants by callers.