Match patterns on Some(x) if some_predicate(x) | None

Forgive me as I'm sure this pattern has been covered, but I have no idea what to search for.

Let's say I have two code paths that depend on an option. Here's what I want to do:

let x: Option<i32> = Some(42);
match {
  (Some(n) if n == 42) | None => {
    // A body which does NOT need n
  }
  Some(n) /* inner not equal to 42 */ => {
    // A body which may or may not need the value of n
  }
}

As far as I am aware, any or'd pattern in a match arm must share all of the same variables assignments. Is there a way to do this? I could write a closure and just call it in two different match arms, but is there a more idiomatic way?

One way is to normalize the Option to None when the value is 42.

    let m = match x.and_then(|x| (x != 42).then_some(x)) {
            None => {
                // A body which does NOT need n
            },
            Some(n) /* inner not equal to 42 */ => {
                // A body which may or may not need the value of n
            },
        };

Playground (fixed)

But I suppose you were hoping for a match expression alone.


Oh, using filter is cleaner:

    let m = match x.filter(|x| *x != 42) {
2 Likes

I was, but this gets me there and I think I can work with it. Thanks!

1 Like

TBF, I prefer the closure call way much more than this combinator approach. The readability suffers too much with more than 1 combinator, for me at least.

1 Like

Yeah I often forget that Option<> has many of the functional-like methods that iterators to. Thanks for the help!

1 Like

For your specific example, that is if you can statically name the x you want to match against this would just work:

let x: Option<i32> = Some(42);
match x {
    Some(42) | None => {
        // A body which does NOT need n
    }
    Some(n) => {
        // A body which may or may not need the value of n
    }
}
3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.