Understanding Rust Enums: Features and Usage

Introduction to Rust Enums

Enums in Rust are unique among programming languages because they allow each variant to hold different types of data.

Defining, Assigning, and Printing Enums

Rust enums have several distinctive characteristics:

  • Enum variants can contain data or be simple
  • When variants contain data, different instances can hold different types
  • Enum variant names must folow specific naming conventions
  • Enums can have methods, similar to structs

Enum Examples


#[derive(Debug)]
enum Gender {
    Male,
    Female,
    NonBinary
}

// Enum with associated data
#[derive(Debug)]
enum Hue {
    Red,
    Blue = 5
}

// Enum with multiple variants containing data of the same type
#[derive(Debug, PartialEq)]
enum Performance {
    Excellent(u32, String),
    Good(u32, String),
    NeedsImprovement(u32, String)
}

// Implementation of methods for enum
impl Performance {
    fn display(&self) {
        match self {
            Performance::Excellent(score, comment) => println!("Rating: {} - {}", score, comment),
            Performance::Good(score, comment) => println!("Rating: {} - {}", score, comment),
            Performance::NeedsImprovement(score, comment) => println!("Rating: {} - {}", score, comment)
        }
    }
}

#[derive(Debug)]
enum Food<'a>{
    Vegetables([String;5]),
    Poultry,
    Pork,
    BeefLamb,
    Seafood,
    Grains,
    Fruits(&'a str, &'a str, &'a str)
}

fn main() {
    let gender = Gender::Male;
    println!("{:?}", gender);
    
    let rating = Hue::Blue;
    println!("{:?}", rating);
    
    let red = Hue::Red;
    println!("{:?}", red);

    let excellent = Performance::Excellent(95, String::from("Outstanding"));
    let good = Performance::Good(80, String::from("Satisfactory"));
    excellent.display();
    println!("{:?}", excellent);
    
    if excellent == good {
        println!("They're equal");
    } else {
        println!("They're not equal");
    }

    let fruit_basket = Food::Fruits("Apple", "Banana", "Orange");
    println!("{:?}", fruit_basket);
    display_fruit(fruit_basket);
    
    let veggies = Food::Vegetables(["Broccoli".to_string(), "Carrot".to_string(), "Spinach".to_string(), "Kale".to_string(), "Lettuce".to_string()]);
    println!("{:?}", veggies);
}

fn display_fruit<'a>(food: Food<'a>) {
    if let Food::Fruits(first, second, third) = food {
        println!("Fruit selection: {}, {}, {}", first, second, third);
    } else {
        println!("This item is not a fruit.");
    }
}

The Special Option Enum

Option<T> is a built-in Rust enum defined in the standard library:


enum Option<T> {
    Some(T),
    None
}

Key features of Option:

  • It's included in Rust's prelude, so no explicit import is needed
  • Its variants (Some and None) can be used without the Option:: prefix
  • It provides useful methods like is_some(), is_none(), and unwrap()
  • It can be used as function parameters

Option Example


fn main() {
    let present_value = Some(42); // Type is Option<i32>
    let text = Some("Hello Rust"); // Type is Option<&str>
    let empty_value: Option<i32> = None; // Type is Option<i32>
    
    println!("Present value: {:?}", present_value);
    println!("Text: {:?}", text);
    println!("Empty value: {:?}", empty_value);
    println!("Is empty: {:?}", empty_value.is_none());
}
</i32></i32></i32>

Matching with Enums

Rust's match expression provides powerful pattern matching for enums:

  • Match is exhaustive - all possibilities must be handled
  • It supports matching single values, multiple values, and all value
  • It uses the underscore (_) to match any value
  • Once a match is found, execution stops (no fall-through)

Match Example


#[derive(Debug)] 
enum Era{Classic,Modern}

enum Coin{Penny(Era),Nickel,Dime,Quarter,HalfDollar,Dollar}
enum Civilization{Chinese(Era),European,American,African}

fn main(){
    let coin = Coin::Nickel;
    let dollar = Coin::Dollar;
    process_coin(coin);
    process_coin(dollar);

    let civilization = Civilization::Chinese(Era::Classic);
    let european_civ = Civilization::European;
    process_civilization(civilization);
    process_civilization(european_civ);
}

fn process_coin(coin:Coin){
    match coin{
        Coin::Penny(Era::Classic) => println!("Classic penny"),  // Match specific value
        Coin::Penny(_) => println!("Any penny"),   // Match all values
        Coin::Penny(Era::Modern) | Coin::Penny(Era::Classic) => println!("Any penny variant", // Match multiple values
        Coin::Nickel => println!("Nickel"),
        Coin::Dime => println!("Dime"),
        Coin::Quarter => println!("Quarter"),
        other => println!("Other coin: {:?}", other),
        _=> println!("Unreachable pattern") 
    };
}

fn process_civilization(civ:Civilization){
    match civ {
        Civilization::Chinese(era) => println!("Ancient Chinese culture: {:?}", era),
        Civilization::European => println!("Innovative European cultures"),
        _ => println!("Other civilization: {:?}", civ)
    };
}

The if let Syntax Sugar

Rust provides if let as a concise alternative to match when you only need to match one pattern:

if let Example


#[derive(Debug)] 
enum Period{GoldenAge,Modern}

enum Currency{Cent(Period),FiveCents,TenCents,FiftyCents}

fn main(){
    let currency = Currency::Cent(Period::GoldenAge);
    
    // Traditional match
    match currency{
        Currency::Cent(Period::GoldenAge) => println!("Golden age currency?"),
        _=>println!("Not a golden age currency")
    }

    // Using if let
    if let Currency::Cent(Period::GoldenAge) = currency{
        println!("Golden age currency?");
    } else {  
        println!("Not a golden age currency");
    }
    
    // if let without else
    if let Currency::Cent(Period::Modern) = currency{
        println!("Modern currency");
    }
}

Conclusion

Rust enums offer unique capabilities compared to enums in other languages, particularly in their ability to associate different types of data with variants. The exhaustive matching ansures type safety, while features like Option provide a standardized way to handle potentially missing values. The if let syntax offers a convenient shorthand for simple pattern matching scenarios.

Tags: rust Enums pattern-matching option-type if-let

Posted on Wed, 24 Jun 2026 17:18:27 +0000 by suthen_cowgirl