65

I want to apply filter on an iterator and I came up with this one and it works, but it's super verbose:

.filter(|ref my_struct| match my_struct.my_enum { Unknown => false, _ => true })

I would rather write something like this:

.filter(|ref my_struct| my_struct.my_enum != Unknown)

This gives me a compile error

binary operation `!=` cannot be applied to type `MyEnum`

Is there an alternative to the verbose pattern matching? I looked for a macro but couldn't find a suitable one.

Shepmaster
  • 326,504
  • 69
  • 892
  • 1,159
Christoph
  • 23,839
  • 25
  • 91
  • 129

3 Answers3

116

Use matches!, e.g.:

matches!(my_struct.my_enum, Unknown)

Alternatively, you can use PartialEq trait, for example, by #[derive]:

#[derive(PartialEq)]
enum MyEnum { ... }

Then your "ideal" variant will work as is. However, this requires that MyEnum's contents also implement PartialEq, which is not always possible/wanted.

Andrew Marshall
  • 92,562
  • 20
  • 215
  • 211
Vladimir Matveev
  • 108,001
  • 30
  • 262
  • 276
11

I'd use pattern matching, but I'd move it to a method on the enum so that the filter closure is tidier:

#[derive(Debug)]
enum Thing {
    One(i32),
    Two(String),
    Unknown,
}

impl Thing {
    fn is_unknown(&self) -> bool {
        match *self {
            Thing::Unknown => true,
            _ => false,
        }
    }
}

fn main() {
    let things = [Thing::One(42), Thing::Two("hello".into()), Thing::Unknown];
    for t in things.iter().filter(|s| !s.is_unknown()) {
        println!("{:?}", t);
    }
}

You can combine this with the matches macro as well:

fn is_unknown(&self) -> bool {
    matches!(self, Thing::Unknown)
}

See also:

Shepmaster
  • 326,504
  • 69
  • 892
  • 1,159
  • Simple and elegant. It always seems counter-intuitive (for a Rust newbie like myself) that one can't just compare directly, but the "use pattern matching in a method" approach really goes a long way in a few short lines toward encouraging more testable, modular code.. – kevlarr Mar 23 '19 at 11:02
6

You can use if let Some(x) = option { then } idiom with the same if let construct but without destructuring:

if let Unknown = my_struct.my_enum { false } else { true }
Miha_x64
  • 5,304
  • 1
  • 43
  • 60