Question

I am using Rust 1.15.1 and, recently, I stumbled over a problem I could not find a straight forward solution for.

When you look at examples using pattern matching they usually destructure the object in the match expression and continue to work with members within that object. However, I'd like to NOT destructure it, but only match against it and dispatch the complete object (using move semantics) to one of several other functions depending on its properties.

The following code works and does exactly what I need. However, I need to introduce an "artificial" enum type and a second match expression. I wonder if there is a more straight forward and simpler solution?

#[derive(Debug)]
enum Number {
    Constant { value: i32 },
}

fn process_even(n: Number) {
    println!("even: {:?}", n);
}

fn process_odd(n: Number) {
    println!("odd: {:?}", n);
}

fn process(n: Number) {
    enum Action {
        ProcessEven,
        ProcessOdd,
    }

    let action = match n {
        Number::Constant { value: c, .. } if 0 == c % 2 => Action::ProcessEven,
        _ => Action::ProcessOdd,
    };

    match action {
        Action::ProcessEven => process_even(n),
        Action::ProcessOdd => process_odd(n),
    }
}

fn main() {
    process(Number::Constant { value: 4711 });
    process(Number::Constant { value: 2000 });
}
Was it helpful?

Solution

Did you try just using n?

fn process(n: Number) {
    match n {
        Number::Constant { value: c, .. } if c % 2 == 0 => process_even(n),
        _ => process_odd(n)
    }
}

That works because value is i32, which is Copy, which means the compiler can copy it out, without needing to move or borrow it. If you're dealing with more complicated types than that, you might not be able to avoid the second stage.

That said, even in that case, if you've only got two options, you could return true or false. Or you could return process_even/process_odd directly as function pointers from the first match and call that:

fn process(n: Number) {
    let action = match n {
        Number::Constant { value: c, .. } if c % 2 == 0 => process_even as fn(_),
        _ => process_odd
    };

    action(n)
}
Licensed under: CC-BY-SA with attribution
scroll top