Equality operator with pattern?

I saw some code like this today:

enum Foo {
    Bar(u32),
    Baz,
}

// ...

fn is_bar(foo: &Foo) ->  bool {
    match foo {
        Foo::Bar(..) => true,
        _ => false,
    }
}

which is fine, nothing controversial. But I was wondering if there was a way to do something like

fn is_bar(foo: &Foo) -> bool {
    foo == Foo::Bar(..)
}

instead. Obviously the above doesn't compile, but is there a shorter way to say "all I care about is whether enum foo is variant Bar"? Or could there be? I think it'd be cool to have the equality operator work with a pattern on one side, but I have no idea what it would mean if you tried to do that with the other comparison operators, so doing it with == doesn't make much sense. Has this kind of thing been discussed before in the context of rust?

Did you try adding #[derive(Eq, PartialEq)] above the enum?

The problem is that having things like .. or _ in the pattern don't work with ==. Yes PartialEq and Eq are derived, but foo == Foo::Bar(..) is a syntax error because of the .., same with foo == Foo::Bar(_). You can put a value in there and it will work, but if you don't care about the wrapped value and only care about "is this Foo the Bar variant", the patterns don't work with ==

There are 2 solutions:

use std::mem;

enum Foo { A(&'static str), B(i32), C(i32) }

assert_eq!(mem::discriminant(&Foo::A("bar")), mem::discriminant(&Foo::A("baz")));
assert_eq!(mem::discriminant(&Foo::B(1)), mem::discriminant(&Foo::B(2)));
assert_ne!(mem::discriminant(&Foo::B(3)), mem::discriminant(&Foo::C(3)));
#[must_use = "if you intended to assert that this has a value, consider `.unwrap()` instead"]
#[inline]
pub const fn is_some(&self) -> bool {
    matches!(*self, Some(_))
}
4 Likes

you could use the std macro matches!

enum Foo {
    Bar(u32),
    Baz
}

fn is_bar(foo: Foo) -> bool {
    matches!(foo, Foo::Bar(_))
}

fn is_bar_greather(foo: Foo, thresold: u32) -> bool {
    matches!(foo, Foo::Bar(x) if x > thresold)
}

fn main() {
    let m = Foo::Bar(0);
    let m2 = Foo::Bar(10);
    let m3 = Foo::Baz;
    println!("is: {:}", is_bar(m));
    println!("is: {:}", is_bar(m3));
    println!("is: {:}", is_bar_greather(m2, 1));
}
8 Likes

thanks, the matches! macro is exactly what I'm looking for!

thanks, that's exactly what I was looking for!

1 Like

From other languages we're conditioned against <condition> ? true : false, but if we can get past that, then there's also if let:

enum Foo {
    Bar(u32),
    Baz,
}

fn is_bar(foo: &Foo) ->  bool {
    if let Foo::Bar(_) = foo { true } else { false }
}

fn main() {
    let f = Foo::Bar(0);
    assert_eq!(is_bar(&f), true);
    let f = Foo::Baz;
    assert_eq!(is_bar(&f), false);
}
1 Like