Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.4k views
in Technique[技术] by (71.8m points)

rust - How to implement PartialEq for an enum?

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
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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,
        }
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...