2

I have an enum:

enum Numbers {
    A = 1,
}

How can I overload the operator so that I can compare the Numbers enum with another standard number without have to do as u32? If I want to do:

let a = Numbers::A < 4

I think i read somewhere that it's possible to do with some kind of macros? Maybe there is a crate that lets me do this? So far the only thing I have had success with is as u32 but it gets quite tedious to have to write it out every time.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366

1 Answers1

5

You do it the exact same way that you overload an operator for a struct: implement the appropriate std::ops trait.

However, you don't really want to overload the meaning of <, you still wish to perform a comparison.

If you run the code you typed, the compiler tells you what to do:

error[E0369]: binary operation `<` cannot be applied to type `Numbers`
 --> src/main.rs:6:13
  |
6 |     let a = Numbers::A < 4;
  |             ^^^^^^^^^^^^^^
  |
  = note: an implementation of `std::cmp::PartialOrd` might be missing for `Numbers`

So, implement PartialOrd:

#[derive(Copy, Clone)]
enum Numbers {
    A = 1,
}

use std::cmp::Ordering;

impl PartialEq<i32> for Numbers {
    fn eq(&self, other: &i32) -> bool {
        (*self as i32).eq(other)
    }
}

impl PartialOrd<i32> for Numbers {
    fn partial_cmp(&self, other: &i32) -> Option<Ordering> {
        (*self as i32).partial_cmp(other)
    }
}

fn main() {
    let a = Numbers::A < 4;
}

As Sven Marnach points out:

It may be worth pointing out that this implementation only allows comparisons with Numbers on the left-hand side and i32 on the right-hand side. Comparisons like 4 > Numbers::A and Numbers.A < Numbers.B would require separate implementations. In addition, since you are dealing with integers, you would also want to implement Ord and Eq, so for all combinations of operands you end up with twelve trait implementations.

Of course, it depends on your exact cases:

  • if you want to compare Numbers to Numbers, you might be able to #[derive(PartialOrd)].
  • if you want Eq, you can derive it.
  • you can write macros to reduce some of the redundancy.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 2
    It may be worth pointing out that this implementation only allows comparisons with `Numbers` on the left-hand side and `i32` on the right-hand side. Comparisons like `4 > Numbers::A` and `Numbers.A < Numbers.B` would require separate implementations. In addition, since you are dealing with integers, you would also want to implement `Ord` and `Eq`, so for all combinations of operands you end up with twelve trait implementations. – Sven Marnach Oct 31 '18 at 13:40