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. Data Modeling with enum

Data Modeling with enum

Rust enums can hold different data depending on the variant, making it possible to safely model complex domains. They are commonly used in practical patterns such as state machines and the command pattern.

Syntax

// An enum representing payment methods.
#[derive(Debug)]
enum Payment {
    Cash(f64),
    CreditCard { number: String, amount: f64 },
    CryptoCurrency { coin: String, wallet: String, amount: f64 },
}

// State machine pattern: represents a connection state.
#[derive(Debug)]
enum ConnectionState {
    Disconnected,
    Connecting { host: String, port: u16 },
    Connected { session_id: u64, latency_ms: u32 },
    Error(String),
}

Common Usage Patterns

PatternDescription
State machineEach variant represents a state of the system. Invalid state transitions can be prevented at compile time.
Command patternEach variant represents a single operation (command).
AST (Abstract Syntax Tree)Recursive enums represent the structure of a program (requires wrapping with Box<T>).
Error typeEach variant represents a distinct kind of failure.
Inside Option<T>Some(T) / None represents whether a value is present.
Inside Result<T, E>Ok(T) / Err(E) represents success or failure.

Sample Code

// An enum representing the status of a task.
#[derive(Debug)]
enum TaskStatus {
    Todo,
    InProgress { started_at: String, assignee: String },
    Done { completed_at: String },
    Blocked(String),  // Reason for being blocked
}

#[derive(Debug)]
struct Task {
    id: u32,
    title: String,
    status: TaskStatus,
}

impl Task {
    fn is_done(&self) -> bool {
        matches!(self.status, TaskStatus::Done { .. })
    }

    fn summary(&self) -> String {
        match &self.status {
            TaskStatus::Todo =>
                format!("[{}] {} - Not started", self.id, self.title),
            TaskStatus::InProgress { assignee, .. } =>
                format!("[{}] {} - In progress by {}", self.id, self.title, assignee),
            TaskStatus::Done { completed_at } =>
                format!("[{}] {} - Completed on {}", self.id, self.title, completed_at),
            TaskStatus::Blocked(reason) =>
                format!("[{}] {} - Blocked: {}", self.id, self.title, reason),
        }
    }
}

// A recursive enum representing JSON-like data.
#[derive(Debug)]
enum JsonValue {
    Null,
    Bool(bool),
    Number(f64),
    Str(String),
    Array(Vec<JsonValue>),
}

impl JsonValue {
    fn to_string(&self) -> String {
        match self {
            JsonValue::Null => "null".to_string(),
            JsonValue::Bool(b) => b.to_string(),
            JsonValue::Number(n) => n.to_string(),
            JsonValue::Str(s) => format!("\"{}\"", s),
            JsonValue::Array(arr) => {
                let items: Vec<String> = arr.iter().map(|v| v.to_string()).collect();
                format!("[{}]", items.join(", "))
            }
        }
    }
}

fn main() {
    let tasks = vec![
        Task {
            id: 1,
            title: String::from("Requirements"),
            status: TaskStatus::Done {
                completed_at: String::from("2024-01-10"),
            },
        },
        Task {
            id: 2,
            title: String::from("Design"),
            status: TaskStatus::InProgress {
                started_at: String::from("2024-01-11"),
                assignee: String::from("Alice"),
            },
        },
        Task {
            id: 3,
            title: String::from("Implementation"),
            status: TaskStatus::Blocked(String::from("Waiting for design")),
        },
        Task {
            id: 4,
            title: String::from("Testing"),
            status: TaskStatus::Todo,
        },
    ];

    for task in &tasks {
        println!("{}", task.summary());
    }

    let done_count = tasks.iter().filter(|t| t.is_done()).count();
    println!("Completed tasks: {}/{}", done_count, tasks.len());

    // Example usage of JsonValue.
    let data = JsonValue::Array(vec![
        JsonValue::Number(1.0),
        JsonValue::Str(String::from("hello")),
        JsonValue::Bool(true),
        JsonValue::Null,
    ]);
    println!("JSON: {}", data.to_string());
}

Overview

Designing with Rust enums realizes the concept of "making illegal states unrepresentable." For example, because session_id only exists in the Connected variant, any code that tries to access session_id before a connection is established will result in a compile error.

The matches!() macro is a utility for writing concise match expressions. Use it when you need to check whether a value matches a specific variant and get a bool result.

For the basics of defining enums, see enum / variant definition.

If you find any errors or copyright issues, please .