#[derive(Eq)]
{
// Attributes available to this derive:
#[eq]
}
Available on crate feature
eq only.Expand description
§Using #[derive(Eq)] and #[derive(PartialEq)]
Deriving Eq/PartialEq works by checking whether two values are equal according
to their type structure.
§Structural equality
Deriving Eq/PartialEq for enums/structs works in a similar way to the one in std,
by comparing all the available fields, but, in the contrast:
- Does not overconstrain generic parameters.
- Implements
PartialEq::ne()method as well, to propagate possible efficient implementations of this method from the underlying types.
§Structs
For structs all the available fields are checked for equality.
trait Trait {
type Assoc;
}
impl<T: ?Sized> Trait for T {
type Assoc = u8;
}
#[derive(Debug, Eq, PartialEq)]
struct Foo<A, B, C: Trait + ?Sized> {
a: A,
b: PhantomData<B>,
c: C::Assoc,
}
#[derive(Debug)]
struct NoEq;
assert_eq!(Foo::<_, NoEq, NoEq> { a: 3, b: PhantomData, c: 0 }, Foo { a: 3, b: PhantomData, c: 0 });
assert_ne!(Foo::<_, NoEq, NoEq> { a: 3, b: PhantomData, c: 0 }, Foo { a: 0, b: PhantomData, c: 3 });This generates code equivalent to:
impl<A, B, C: Trait + ?Sized> PartialEq for Foo<A, B, C>
where
A: PartialEq,
PhantomData<B>: PartialEq, // `B: PartialEq` is generated by `std` instead
C::Assoc: PartialEq, // `C: PartialEq` is generated by `std` instead
{
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self { a: self_0, b: self_1, c: self_2 }, Self { a: other_0, b: other_1, c: other_2 }) => {
self_0 == other_0 && self_1 == other_1 && self_2 == other_2
}
}
}
fn ne(&self, other: &Self) -> bool {
match (self, other) {
(Self { a: self_0, b: self_1, c: self_2 }, Self { a: other_0, b: other_1, c: other_2 }) => {
self_0 != other_0 || self_1 != other_1 || self_2 != other_2
}
}
}
}
impl<A, B, C: Trait + ?Sized> Eq for Foo<A, B, C>
where
Self: PartialEq,
A: Eq,
PhantomData<B>: Eq, // `B: Eq` is generated by `std` instead
C::Assoc: Eq, // `C: Eq` is generated by `std` instead
{}§Enums
For enums the first check is whether these two values represent the same variant, and after that we check fields equality.
#[derive(Debug, Eq, PartialEq)]
enum Foo<A, B, C: Trait + ?Sized> {
A(A),
B { b: PhantomData<B> },
C(C::Assoc),
}
assert_eq!(Foo::<_, NoEq, NoEq>::A(3), Foo::A(3));
assert_ne!(Foo::<_, NoEq, NoEq>::A(3), Foo::A(0));
assert_eq!(Foo::<u16, NoEq, NoEq>::B { b: PhantomData }, Foo::B { b: PhantomData });
assert_eq!(Foo::<i32, NoEq, NoEq>::C(3), Foo::C(3));
assert_ne!(Foo::<i32, NoEq, NoEq>::C(3), Foo::C(0));This generates code equivalent to:
impl<A, B, C: Trait + ?Sized> PartialEq for Foo<A, B, C>
where
A: PartialEq,
PhantomData<B>: PartialEq, // `B: PartialEq` is generated by `std` instead
C::Assoc: PartialEq, // `C: PartialEq` is generated by `std` instead
{
fn eq(&self, other: &Self) -> bool {
std::mem::discriminant(self) == std::mem::discriminant(other) &&
match (self, other) {
(Self::A(self_0), Self::A(other_0)) => { self_0 == other_0 }
(Self::B { b: self_0 }, Self::B { b: other_0 }) => { self_0 == other_0 }
(Self::C(self_0), Self::C(other_0)) => { self_0 == other_0 }
_ => unsafe { std::hint::unreachable_unchecked() }
}
}
fn ne(&self, other: &Self) -> bool {
std::mem::discriminant(self) != std::mem::discriminant(other) ||
match (self, other) {
(Self::A(self_0), Self::A(other_0)) => { self_0 != other_0 }
(Self::B { b: self_0 }, Self::B { b: other_0 }) => { self_0 != other_0 }
(Self::C(self_0), Self::C(other_0)) => { self_0 != other_0 }
_ => unsafe { std::hint::unreachable_unchecked() }
}
}
}
impl<A, B, C: Trait + ?Sized> Eq for Foo<A, B, C>
where
Self: PartialEq,
A: Eq,
PhantomData<B>: Eq, // `B: Eq` is generated by `std` instead
C::Assoc: Eq, // `C: Eq` is generated by `std` instead
{}§Ignoring
Both #[eq(skip)] and #[partial_eq(skip)] attributes could be used to ignore
fields, a whole struct or enum variants in the expansion.
#[derive(Debug)]
struct NoEq; // doesn't implement `Eq`/`PartialEq`
#[derive(Debug, Eq, PartialEq)]
struct Foo {
num: i32,
// This attribute is seen by both `Eq` and `PartialEq` macros,
// so the repetition is unnecessary.
#[eq(skip)] // or #[eq(ignore)]
ignored: f32,
}
#[derive(Debug, Eq, PartialEq)]
// This attribute is also seen by both `Eq` and `PartialEq` macros.
// Makes all fields of this struct being ignored.
#[partial_eq(skip)] // or #[partial_eq(ignore)]
struct Bar(f32, NoEq);
#[derive(Debug, Eq, PartialEq)]
enum Enum {
Foo(i32, #[eq(skip)] NoEq),
#[eq(skip)]
Bar(NoEq),
Baz,
}
assert_eq!(Foo { num: 0, ignored: 1.0 }, Foo { num: 0, ignored: 1.0 });
assert_eq!(Foo { num: 0, ignored: 1.0 }, Foo { num: 0, ignored: 2.0 });
assert_ne!(Foo { num: 0, ignored: 1.0 }, Foo { num: 1, ignored: 1.0 });
assert_eq!(Bar(0.0, NoEq), Bar(0.0, NoEq));
assert_eq!(Bar(0.0, NoEq), Bar(1.0, NoEq));
assert_eq!(Enum::Foo(0, NoEq), Enum::Foo(0, NoEq));
assert_ne!(Enum::Foo(0, NoEq), Enum::Foo(1, NoEq));
assert_eq!(Enum::Bar(NoEq), Enum::Bar(NoEq));
assert_eq!(Enum::Baz, Enum::Baz);
// NOTE: Different variants are still not equal despite being ignored!
// Ignoring a variant only ignores all its fields during comparison.
assert_ne!(Enum::Foo(0, NoEq), Enum::Bar(NoEq));
assert_ne!(Enum::Foo(0, NoEq), Enum::Baz);
assert_ne!(Enum::Bar(NoEq), Enum::Baz);This generates code equivalent to:
impl PartialEq for Foo {
fn eq(&self, __other: &Self) -> bool {
match (self, __other) {
(Self { num: __self_0, .. }, Self { num: __other_0, .. }) => { __self_0 == __other_0 }
}
}
fn ne(&self, __other: &Self) -> bool {
match (self, __other) {
(Self { num: __self_0, .. }, Self { num: __other_0, .. }) => { __self_0 != __other_0 }
}
}
}
impl Eq for Foo
where
i32: Eq,
{}
impl PartialEq for Bar {
fn eq(&self, __other: &Self) -> bool { true }
}
impl Eq for Bar {}
impl PartialEq for Enum {
fn eq(&self, __other: &Self) -> bool {
std::mem::discriminant(self) == std::mem::discriminant(__other) &&
match (self, __other) {
(Self::Foo(__self_0, _, ), Self::Foo(__other_0, _, )) => { __self_0 == __other_0 }
_ => true,
}
}
fn ne(&self, __other: &Self) -> bool {
std::mem::discriminant(self) != std::mem::discriminant(__other) ||
match (self, __other) {
(Self::Foo(__self_0, _, ), Self::Foo(__other_0, _, )) => { __self_0 != __other_0 }
_ => false,
}
}
}