8

Hey I'm learning rust and trying to figure out why I can't directly compare two instances of a very simple Enum, I've tried using matches! (doesn't work) and #[derive(Eq)] (just forwards the problem to the impl

Here's a snippet demonstrating my issue, and it's output.

#[derive(Debug)]
pub enum MyEnum {
    Enum1,
    Enum2,
    Enum3
}

#[derive(Debug)]
pub enum ThingEnum {
    NoOp,
    Enum(MyEnum)
}

pub fn test_enum_equate() {
    let mut enum1 = Vec::new();
    enum1.push(MyEnum::Enum1);
    enum1.push(MyEnum::Enum2);
    enum1.push(MyEnum::Enum3);

    let mut expr = vec![
        ThingEnum::NoOp,
        ThingEnum::Enum(MyEnum::Enum1),
        ThingEnum::Enum(MyEnum::Enum2),
        ThingEnum::NoOp,
        ThingEnum::Enum(MyEnum::Enum3)
    ];

    for myenum in enum1.iter() {
        for entry in expr.iter() {
            match entry {
                ThingEnum::NoOp => continue,
                ThingEnum::Enum(en) => {
                    // Check if they are the same
                    println!("matches!({:?}, {:?}) = {}",
                        myenum, en, matches!(myenum, en)
                    );
                    // Need to implement partial eq, WHY?
                    // println!("{:?} == {:?} -> {}",
                    //     myenum, en, myenum == en
                    // );
                }
            }
        }
    }
}

The output is:

matches!(Enum1, Enum1) = true
matches!(Enum1, Enum2) = true
matches!(Enum1, Enum3) = true
matches!(Enum2, Enum1) = true
matches!(Enum2, Enum2) = true
matches!(Enum2, Enum3) = true
matches!(Enum3, Enum1) = true
matches!(Enum3, Enum2) = true
matches!(Enum3, Enum3) = true

Which isn't the desired effect.

If I just used numbers or strings, this would work fine, but I feel like the usefulness of an Enum should be that there is no associated value, so why is this so difficult to make work?

Spencer H
  • 450
  • 1
  • 6
  • 17

1 Answers1

14

Rust equality comes in two forms, PartialEq and Eq. Every Eq is also PartialEq, but the reverse is not true. Specifically, PartialEq only requires that the operation be a partial equivalence relation, while Eq makes the stronger guarantee that the relation is an equivalence relation.

A good example of types which are PartialEq but not Eq are the floating-point types f32 and f64, both of which have a special NaN value which is not equal to itself. In data structures like hashmaps and binary trees, having a value that is not equal to itself is disastrous, so data structures like those require a type that is Eq, while f32 is only PartialEq. Go try to make a HashSet<f32>. You'll run into some compiler errors pretty quick.

In your case, however, you don't really need to worry about any of this. Since your type is a simple enum, you can simply derive both PartialEq and Eq.

#[derive(Debug, PartialEq, Eq)]
pub enum MyEnum { ... }

Then == will work exactly as you'd like it to.

Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116