4

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 });
}
Jonny Dee
  • 957

1 Answers1

2

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)
}
DK.
  • 228
  • You are right! I simplified the code too much. I should have used something which is NOT Copyas value. What you suggested is exactly what I had in mind and actually tired to do. However, as you already mentioned, this seems to only work with members that implement Copy trait. Using a 'bool' works in the special case of two alternatives, but one would make use of the same mechanism. Using function pointers might be the simple solution I am looking for. I'll try, thanks :-) – Jonny Dee Mar 12 '17 at 03:51
  • 1
    @JonnyDee I added an example of using a function pointer. – DK. Mar 12 '17 at 03:56