Course contentsShow
← Rust
Lesson 814 of 1,9106. Generics and Static DispatchFree lesson

Advanced Pattern Matching for Generic Results

Use generic result-handling wrappers to clean up nested business logic.

In this lesson, you will learn how to use generic wrapper types to unify error handling and simplify pattern matching across disparate business logic functions.

The Problem of "Nesting Hell"

When your business logic performs multiple operations that each return different error types, you often end up with deeply nested match statements. Imagine you have a fetch_user returning UserError and a save_order returning OrderError. Handling both inside a single flow forces you to wrap or convert them manually, leading to repetitive code that masks the actual logic.

Creating a Generic Result Wrapper

Instead of matching every specific error type repeatedly, we can define a generic wrapper that standardizes how we interact with the Result enum. By implementing patterns that inspect these results, we can centralize our logic.

Consider a simple generic handler that processes any result:

struct ResultHandler<T, E>(Result<T, E>);

impl<T, E: std::fmt::Display> ResultHandler<T, E> {
    fn process<F, G>(self, on_success: F, on_error: G) 
    where 
        F: FnOnce(T), 
        G: FnOnce(E) 
    {
        match self.0 {
            Ok(val) => on_success(val),
            Err(err) => on_error(err),
        }
    }
}

Streamlining the Logic

By using a generic structure like ResultHandler, your business logic stops worrying about the specific Result type and instead focuses on what to do with the outcome. You can now chain your operations without writing exhaustive match arms for every unique error type in your crate.

For example, when you perform an action, you simply pass it to the handler:

fn handle_app_logic() {
    let result = perform_task(); // Returns Result<Success, Error>
    
    ResultHandler(result).process(
        |data| println!("Success: {:?}", data),
        |err| eprintln!("Failed: {}", err),
    );
}

This pattern abstracts the match away. Because the wrapper is generic, it remains type-safe while allowing you to keep your core business functions clean, readable, and decoupled from the specific error-handling mechanics of your modules.

Key Takeaway: Use generic wrappers to standardize how your application consumes Results, turning complex nested matching into clean, reusable functional blocks.