37

I have the following definition:

enum Either<T, U> {
    Left(T),
    Right(U),
}

How would I get the equivalent of #[derive(PartialEq)] for this type? I would like to use a match expression, like:

impl<T: PartialEq, U: PartialEq> PartialEq for Either<T, U> {
    fn eq(&self, other: &Either<T, U>) -> bool {
        use Either::*;
        match (*self, *other) {
            (Left(ref a), Left(ref b)) => a == b,
            (Right(ref a), Right(ref b)) => a == b,
            _ => false,
        }
    }
}

This consumes both *self and *other, even though I only need it for the match expression, causing the error:

error[E0507]: cannot move out of borrowed content
 --> src/lib.rs:9:16
  |
9 |         match (*self, *other) {
  |                ^^^^^ cannot move out of borrowed content

error[E0507]: cannot move out of borrowed content
 --> src/lib.rs:9:23
  |
9 |         match (*self, *other) {
  |                       ^^^^^^ cannot move out of borrowed content
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Mario Carneiro
  • 1,548
  • 1
  • 18
  • 32

1 Answers1

56

Normally, you would just use #[derive(PartialEq)], like so:

#[derive(PartialEq)]
enum Either<T, U> {
    Left(T),
    Right(U),
}

This will generate the code to implement the trait for you. The Rust Programming Language describes the implementation details.


Sometimes, you want to implement the trait directly. This may be because the default version is either too specific or too generic.

The error in your case is that you you need to pattern match the references instead of trying to dereference them:

impl<T: PartialEq, U: PartialEq> PartialEq for Either<T, U> {
    fn eq(&self, other: &Self) -> bool {
        use Either::*;

        match (self, other) {
            (&Left(ref a), &Left(ref b)) => a == b,
            (&Right(ref a), &Right(ref b)) => a == b,
            _ => false,
        }
    }
}

When you create a tuple, you would be moving the dereferenced item into the tuple, giving up ownership. When you have a match *foo, you don't have to give up the ownership.

In modern Rust, you can write the same thing with less noise because more implicit referencing / dereferencing occurs when pattern matching:

impl<T: PartialEq, U: PartialEq> PartialEq for Either<T, U> {
    fn eq(&self, other: &Self) -> bool {
        use Either::*;
        match (self, other) {
            (Left(a), Left(b)) => a == b,
            (Right(a), Right(b)) => a == b,
            _ => false,
        }
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Why isn't `#[derive(PartialEq)]` implemented? – starblue Mar 30 '16 at 06:01
  • @starblue What do you mean? As far as I know, `#[derive(PartialEq)]` produces LLVM directly from the compiler, so there is no Rust code to inspect. I wanted to create an impl that produces the same output, as much as possible, as a base for modification. – Mario Carneiro Mar 30 '16 at 10:27
  • 6
    It produces rust code, you just don't see it because it happens during compilation, rather than being in the source. – Steve Klabnik Mar 30 '16 at 18:16
  • Is there such an elegant way to do it with anonymous struct? `(Zebra::Map{map}, Zebra::Map{map}) => ` defines the same identifier twice. Is the best way to define an alias variable and a nested `match`es? – Victor Sergienko Sep 04 '21 at 22:34
  • 1
    @VictorSergienko you'd [rename the fields when pattern matching them](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d75216851a3dd25ddd0c39cfb6dc17f2) – Shepmaster Sep 14 '21 at 20:22
  • Thank you! Probably it's worth extending the example? – Victor Sergienko Sep 14 '21 at 22:24