Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

Rust Dictionary

  1. Home
  2. Rust Dictionary
  3. impl enum / Pattern Branching with match

impl enum / Pattern Branching with match

Since: Rust 1.0(2015)

Rust enums support methods added via impl, and the match expression lets you handle every variant exhaustively. Because the compiler detects any unhandled variants, you get safe, reliable pattern matching.

Syntax

enum Shape {
    Circle(f64),
    Rectangle(f64, f64),
    Triangle(f64, f64, f64),
}

impl Shape {
    fn area(&self) -> f64 {
        match self {
            Shape::Circle(r) => std::f64::consts::PI * r * r,
            Shape::Rectangle(w, h) => w * h,
            Shape::Triangle(a, b, c) => {
                let s = (a + b + c) / 2.0;
                (s * (s - a) * (s - b) * (s - c)).sqrt() // Heron's formula
            }
        }
    }
}

// if let: handles only one specific variant.
if let Shape::Circle(r) = shape {
    println!("Circle radius: {}", r);
}

How to use match and if let

SyntaxDescription
match val { Variant(x) => ... }Handles all variants exhaustively (a compile error occurs if any variant is missing).
_ => ...Wildcard: catches all remaining variants in one arm.
if let Variant(x) = val { ... }Handles only one specific variant. You can also use an else branch.
while let Variant(x) = val { ... }Loops as long as the pattern matches.
Variant(x) if x > 0 => ...Match guard: adds an extra condition after matching a variant.
Variant(x) | Variant2(x) => ...Combines multiple variants into a single arm using |.
impl Enum { fn method(&self) }Adds methods to an enum (same as with structs).

Sample code

sample_enum_impl_match.rs
#[derive(Debug)]
enum TrafficLight {
    Red,
    Yellow,
    Green,
}

impl TrafficLight {
    fn duration_secs(&self) -> u32 {
        match self {
            TrafficLight::Red => 60,
            TrafficLight::Yellow => 5,
            TrafficLight::Green => 45,
        }
    }

    fn can_go(&self) -> bool {
        matches!(self, TrafficLight::Green)
    }

    fn next(&self) -> TrafficLight {
        match self {
            TrafficLight::Red => TrafficLight::Green,
            TrafficLight::Green => TrafficLight::Yellow,
            TrafficLight::Yellow => TrafficLight::Red,
        }
    }
}

#[derive(Debug)]
enum Expr {
    Number(f64),
    Add(Box<Expr>, Box<Expr>),
    Mul(Box<Expr>, Box<Expr>),
    Neg(Box<Expr>),
}

impl Expr {
    fn eval(&self) -> f64 {
        match self {
            Expr::Number(n) => *n,
            Expr::Add(a, b) => a.eval() + b.eval(),
            Expr::Mul(a, b) => a.eval() * b.eval(),
            Expr::Neg(e) => -e.eval(),
        }
    }
}

fn main() {
    // Call methods on an enum.
    let light = TrafficLight::Red;
    println!("{:?}: {} secs, can go?: {}", light, light.duration_secs(), light.can_go());

    let next = light.next();
    println!("Next: {:?}", next);

    // Use if let to handle only one variant.
    let value = Some(42);
    if let Some(n) = value {
        println!("Value: {}", n);
    }

    // Match guards with conditions.
    let numbers = vec![1, -3, 5, -2, 8];
    for &n in &numbers {
        match n {
            x if x > 0 => print!("pos:{} ", x),
            x if x < 0 => print!("neg:{} ", x),
            _ => print!("zero "),
        }
    }
    println!();

    // Evaluate an expression using a recursive enum.
    // (3 + 4) * (-2) = -14
    let expr = Expr::Mul(
        Box::new(Expr::Add(
            Box::new(Expr::Number(3.0)),
            Box::new(Expr::Number(4.0)),
        )),
        Box::new(Expr::Neg(Box::new(Expr::Number(2.0)))),
    );
    println!("(3 + 4) * (-2) = {}", expr.eval());
}

Compile with the following command:

rustc enum_impl_match.rs
./enum_impl_match
Red: 60 secs, can go?: false
Next: Green
Value: 42
Positive:1 Negative:-3 Positive:5 Negative:-2 Positive:8 
(3 + 4) * (-2) = -14

Sample Code 2: Match Guards and Nested Enums

This example uses match guards (if guard) and nests one enum inside another.

enum_impl_match2.rs
#[derive(Debug)]
enum Status {
    Active,
    Inactive,
    Suspended(String),
}

#[derive(Debug)]
struct Character {
    name: String,
    level: u32,
    status: Status,
}

impl Character {
    fn new(name: &str, level: u32, status: Status) -> Self {
        Character {
            name: name.to_string(),
            level,
            status,
        }
    }

    fn describe(&self) -> String {
        match &self.status {
            Status::Active if self.level >= 50 => {
                format!("{}: Elite member (Lv.{})", self.name, self.level)
            }
            Status::Active => {
                format!("{}: Active (Lv.{})", self.name, self.level)
            }
            Status::Inactive => {
                format!("{}: Retired", self.name)
            }
            Status::Suspended(reason) => {
                format!("{}: Suspended - {}", self.name, reason)
            }
        }
    }

    fn is_available(&self) -> bool {
        matches!(&self.status, Status::Active)
    }
}

fn main() {
    let members = vec![
        Character::new("Yagami Iori", 80, Status::Active),
        Character::new("Kusanagi Kyo", 75, Status::Active),
        Character::new("Terry Bogard", 30, Status::Active),
        Character::new("Mai Shiranui", 60, Status::Inactive),
        Character::new("Rugal Bernstein",99, Status::Suspended("missing".to_string())),
    ];

    for m in &members {
        println!("{}", m.describe());
    }

    println!("\nAvailable members:");
    for m in members.iter().filter(|m| m.is_available()) {
        println!("  - {}", m.name);
    }
}

Compile with the following command:

rustc enum_impl_match2.rs
./enum_impl_match2
Yagami Iori: Elite member (Lv.80)
Kusanagi Kyo: Elite member (Lv.75)
Terry Bogard: Active (Lv.30)
Mai Shiranui: Retired
Rugal Bernstein: Suspended - missing

Available members:
  - Yagami Iori
  - Kusanagi Kyo
  - Terry Bogard

Sample Code 3: Multiple Methods in an impl Block

Adding multiple methods to an enum and using match to return computed values.

enum_impl_match3.rs
#[derive(Debug, Clone, PartialEq)]
enum FightStyle {
    Striker,
    Grappler,
    Shooter,
    AllAround,
}

impl FightStyle {
    fn name(&self) -> &str {
        match self {
            FightStyle::Striker => "Striker",
            FightStyle::Grappler => "Grappler",
            FightStyle::Shooter => "Shooter",
            FightStyle::AllAround => "All-Around",
        }
    }

    fn power_rating(&self) -> u32 {
        match self {
            FightStyle::Striker => 90,
            FightStyle::Grappler => 80,
            FightStyle::Shooter => 70,
            FightStyle::AllAround => 85,
        }
    }

    fn counters(&self) -> FightStyle {
        match self {
            FightStyle::Striker => FightStyle::Grappler,
            FightStyle::Grappler => FightStyle::Shooter,
            FightStyle::Shooter => FightStyle::Striker,
            FightStyle::AllAround => FightStyle::AllAround,
        }
    }
}

fn main() {
    let styles = [
        ("Yagami Iori", FightStyle::Striker),
        ("Leona", FightStyle::AllAround),
        ("Ralf Jones", FightStyle::Grappler),
        ("Clark Still", FightStyle::Grappler),
        ("Billy Kane", FightStyle::Shooter),
    ];

    for (name, style) in &styles {
        let counter = style.counters();
        println!(
            "{}: {} (power:{}) → weakness: {}",
            name, style.name(), style.power_rating(), counter.name()
        );
    }
}

Compile with the following command:

rustc enum_impl_match3.rs
./enum_impl_match3
Yagami Iori: Striker (power:90) → weakness: Grappler
Leona: All-Around (power:85) → weakness: All-Around
Ralf Jones: Grappler (power:80) → weakness: Shooter
Clark Still: Grappler (power:80) → weakness: Shooter
Billy Kane: Shooter (power:70) → weakness: Striker

Common Mistakes

Mistake 1: Using self instead of &self, causing ownership to move

Using self in a method signature moves ownership into the method, making the value unusable afterward. Use &self to borrow instead.

ng_self.rs
#[derive(Debug)]
enum Light { Red, Green }

impl Light {
    fn label(self) -> &'static str {
        match self {
            Light::Red => "red",
            Light::Green => "green",
        }
    }
}

fn main() {
    let light = Light::Red;
    println!("{}", light.label());
    println!("{:?}", light);
}

Compile with the following command:

rustc ng_self.rs
error[E0382]: borrow of moved value: `light`

Correct version:

ok_self.rs
#[derive(Debug)]
enum Light { Red, Green }

impl Light {
    fn label(&self) -> &'static str {
        match self {
            Light::Red => "red",
            Light::Green => "green",
        }
    }
}

fn main() {
    let light = Light::Red;
    println!("{}", light.label());
    println!("{:?}", light);
}

Running the above produces the following output:

rustc ok_self.rs && ./ok_self
red
Red

Mistake 2: Defining a method outside the impl block

Methods on an enum must be defined inside an impl block. Writing a method outside causes a compile error.

ng_impl.rs
enum Direction { North, South }

fn Direction::label(&self) -> &str {
    "north"
}

Compile with the following command:

rustc ng_impl.rs
error: expected item, found `::`

Correct version:

ok_impl.rs
enum Direction { North, South }

impl Direction {
    fn label(&self) -> &str {
        match self {
            Direction::North => "north",
            Direction::South => "south",
        }
    }
}

Running the above produces the following output:

rustc ok_impl.rs && ./ok_impl

Mistake 3: Forgetting to cover all variants in match

A match expression must cover every possible variant. When you add a new variant and forget to update an existing match, the compiler reports an error.

ng_match.rs
enum Color { Red, Green, Blue }

fn describe(c: Color) -> &'static str {
    match c {
        Color::Red => "red",
        Color::Green => "green",
    }
}

Compile with the following command:

rustc ng_match.rs
error[E0004]: non-exhaustive patterns: `Blue` not covered

Correct version (add the Blue arm or handle remaining variants with a wildcard):

ok_match.rs
enum Color { Red, Green, Blue }

fn describe(c: Color) -> &'static str {
    match c {
        Color::Red => "red",
        Color::Green => "green",
        Color::Blue => "blue",
    }
}

Running the above produces the following output:

rustc ok_match.rs && ./ok_match

Notes

In Rust, match expressions must cover every variant. Adding a new variant without updating existing match arms causes a compile error, which prevents unhandled cases from slipping through. Use a wildcard arm (_) to handle remaining variants together.

Recursive enums cause a compile error because the compiler cannot determine their size automatically. Wrap the recursive field in a pointer such as Box<Expr> to fix the size.

For details on defining enums and their variants, see enum / variant definitions.

If you find any errors or copyright issues, please .