Sling Academy
Home/Rust/Rust - Avoiding Code Duplication by Collapsing Similar Enum Match Arms

Rust - Avoiding Code Duplication by Collapsing Similar Enum Match Arms

Last updated: January 04, 2025

Code duplication is a common challenge faced by developers, which can lead to longer, more error-prone, and harder-to-maintain codebases. One effective strategy for reducing code duplication is to collapse similar match arms in enums, which is particularly useful in languages like Rust. This article will guide you through the concept of collapsing similar enum match arms, providing examples to illustrate the approach.

Understanding Enums and Matching in Rust

Enums (short for 'enumerations') are a versatile data structure that allow you to define a type by enumerating its possible variants. In Rust, the match construct is often used with enums to handle different possible values.

Consider a simple enum defined in Rust:


enum Color {
    Red,
    Green,
    Blue,
    Yellow
}

In a typical usage, each enum variant is matched to execute specific code:


fn print_color_name(color: Color) {
    match color {
        Color::Red => println!("Red"),
        Color::Green => println!("Green"),
        Color::Blue => println!("Blue"),
        _ => println!("Other color"),
    }
}

If different variants share the same action, it's wasteful and makes the code harder to maintain. Let's explore strategies for collapsing these into a single match arm.

Collapsing Match Arms

The technique of collapsing match arms is based on creatively using the pattern matching capabilities of Rust. Here is how redundancy can be minimized by combining multiple patterns into single match arms:


fn print_color_name(color: Color) {
    match color {
        Color::Red | Color::Blue => println!("Primary color"),
        Color::Green | Color::Yellow => println!("Secondary color"),
    }
}

In this revised example, instead of repeating the println! for Red and Blue, we use the | operator to match both variants under a single arm. This technique reduces duplication and improves code readability.

Advantages of Collapsing Enum Match Arms

Collapsing similar match arms when dealing with enums comes with several benefits:

  • Reduced Code Duplication: Collapsed match arms minimize repetitive code, which shrinks the overall code footprint.
  • Improved Maintainability: Changes made in one place apply to all related variants, thus making maintenance easier.
  • Enhanced Readability: Grouping similar actions together provides clarity on how similar items are handled structurally.

Advanced Techniques

Consider a real-world scenario where variants carry data. Rust's match arms can be collapsed even when they share similar logic with additional values:


enum LogLevel {
    Info(String),
    Warning(String),
    Error(String)
}

fn log_message(level: LogLevel) {
    match level {
        LogLevel::Info(msg) | LogLevel::Warning(msg) => {
            println!("{}", msg);
        }
        LogLevel::Error(msg) => {
            eprintln!("ERROR: {}", msg);
        }
    }
}

Here, both Info and Warning log levels share the action of printing the message, which is handled in a single match arm. On the other hand, Error is treated differently by printing to the standard error.

Conclusion

By learning to use pattern matching effectively, you can eliminate redundant match arms, creating cleaner and more performance-efficient code. The match operator in Rust is a powerful tool that, when used cleverly, can greatly reduce code duplication and enhance the maintainability of projects relying on enums.

Next Article: Refactoring Big Switch-Case Logic from Other Languages to Rust Enums

Previous Article: Rust - Combining Enum Variants with Shared Data Using `Arc` or `Rc`

Series: Enum and Pattern Matching in Rust

Rust

You May Also Like

  • E0557 in Rust: Feature Has Been Removed or Is Unavailable in the Stable Channel
  • Network Protocol Handling Concurrency in Rust with async/await
  • Using the anyhow and thiserror Crates for Better Rust Error Tests
  • Rust - Investigating partial moves when pattern matching on vector or HashMap elements
  • Rust - Handling nested or hierarchical HashMaps for complex data relationships
  • Rust - Combining multiple HashMaps by merging keys and values
  • Composing Functionality in Rust Through Multiple Trait Bounds
  • E0437 in Rust: Unexpected `#` in macro invocation or attribute
  • Integrating I/O and Networking in Rust’s Async Concurrency
  • E0178 in Rust: Conflicting implementations of the same trait for a type
  • Utilizing a Reactor Pattern in Rust for Event-Driven Architectures
  • Parallelizing CPU-Intensive Work with Rust’s rayon Crate
  • Managing WebSocket Connections in Rust for Real-Time Apps
  • Downloading Files in Rust via HTTP for CLI Tools
  • Mocking Network Calls in Rust Tests with the surf or reqwest Crates
  • Rust - Designing advanced concurrency abstractions using generic channels or locks
  • Managing code expansion in debug builds with heavy usage of generics in Rust
  • Implementing parse-from-string logic for generic numeric types in Rust
  • Rust.- Refining trait bounds at implementation time for more specialized behavior