Doug
Doug

Reputation: 35106

Is it possible to implement the equals operator for different types in Rust?

As seen in How can an operator be overloaded for different RHS types and return values? you can implement some operators, eg. Add on multiple types using a work around.

Is a similar thing possible for the PartialEq trait?

I've tried various things, but the closest I can get is creating a fake trait Foo, implementing PartialEq on &Foo (since it's a trait you can't implement it on Foo) and then doing:

let x:Bar = ...
let y:FooBar = ...
if &x as &Foo == &y as &Foo {
  ...
}

The Equiv trait looks like it should be used for this, but as far as I can tell, implementing Equiv doesn't have anything to do with the == operator.

Is there a way to do this?

Upvotes: 6

Views: 4280

Answers (2)

Andria
Andria

Reputation: 5065

PartialEq implementations can take any right-hand side type

As of Rust 1.0.0 (2015), PartialEq (== and !=) allows you to supply any type (sized or not) as the right-hand side's type when you are implementing it. You can also use traits as both the left-hand and right-hand side when implementing PartialEq.

Comparing two different types

Implementing PartialEq for two different types is very simple. The trait PartialEq takes a generic type called Rhs that specifies what type you will be comparing with the type that you are implementing PartialEq for.

impl PartialEq<B> for A {
    fn eq(&self, other: &B) -> bool {
        /* ... */
    }
}

Comparing any types that implement a specific trait

You can use the dyn 1 keyword to specify a trait as a type, which allows us to implement PartialEq for or with that trait.

trait Foo { /* ... */ }
impl PartialEq<dyn Foo> for dyn Foo {
    fn eq(&self, other: &dyn Foo) -> bool {
        /* ... */
    }
}

Working example of two-type ==

Below is a working example of writing and testing PartialEq between two different structs, A and B.

struct A {
    thing: String,
    stuff: u8,
}

struct B {
    optional_thing: Option<String>,
    extra: String,
}

impl PartialEq<B> for A {
    fn eq(&self, other: &B) -> bool {
        if let Some(thing_b) = &other.optional_thing {
            *thing_b == self.thing
        } else {
            false
        }
    }
}

fn main() {
    let a1 = A {
        thing: "Hello".to_owned(),
        stuff: 0,
    };
    let a2 = A {
        thing: "World".to_owned(),
        stuff: 32,
    };

    let b1 = B {
        optional_thing: Some("Hello".to_owned()),
        extra: "...".to_owned(),
    };
    let b2 = B {
        optional_thing: None,
        extra: "".to_owned(),
    };

    assert!(a1 == b1, "a1 and b1 should be equal");
    assert!(a1 != b2, "a1 should not equal b2");

    assert!(a2 != b1, "a2 should not equal b1");
    assert!(a2 != b2, "a2 should not equal b2");
}

Upvotes: 2

huon
huon

Reputation: 102016

The == operator is only overridable via the PartialEq trait, and thus usable with matching types. Any other form of equality/equivalence needs a custom function/method, you can use the Equiv trait, although values that are equivalent should theoretically also have the same hash (or else HashMap.find_equiv won't work as you expect).

Upvotes: 5

Related Questions