pub trait PartialEq<Rhs: ?Sized = Self> {
// Required method
fn eq(&self, other: &Rhs) -> bool;
// Provided method
fn ne(&self, other: &Rhs) -> bool { ... }
}
Expand description
Trait 等值比较。
x.eq(y)
也可以写成 x == y
,x.ne(y)
,也可以写成 x != y
。
在本文档的其余部分中,我们使用了更易于阅读的中缀符号。
对于没有完全等价关系的类型,这个 trait 允许部分相等。
例如,在浮点数 NaN != NaN
中,因此浮点类型实现 PartialEq
,但不实现 Eq
。
形式上来说,当 Rhs == Self
时,这个 trait 对应一个 partial equivalence relation。
实现必须确保 eq
和 ne
彼此一致:
a != b
当且仅当!(a == b)
。
ne
的默认实现提供了这种一致性,并且几乎总是足够的。没有很好的理由不应该覆盖它。
如果 Self
和 Rhs
也实现了 PartialOrd
或 Ord
,则它们的方法也必须与 PartialEq
一致 (具体要求请参见那些 traits 的文档)。
通过派生一些 traits 并手动实现其他一些行为,很容易使它们不以为然。
等式关系 ==
必须满足以下条件 (对于所有类型为 A
、B
、C
的 a
、b
、c
) :
-
对称: 如果
A: PartialEq<B>
和B: PartialEq<A>
,则a == b
意味着 ’b == a`; 和 -
可传递: 如果
A: PartialEq<B>
和B: PartialEq<C>
以及A: PartialEq<C>
,然后a == b
,并且b == c
暗示了a == c
。
请注意,B: PartialEq<A>
(symmetric) 和 A: PartialEq<C>
(transitive) 强制不是强制存在的,但是这些要求只要存在就适用。
Derivable
该 trait 可以与 #[derive]
一起使用。在结构体上 derive
d 时,如果所有字段都相等,则两个实例相等; 如果任何字段不相等,则两个实例不相等。当在枚举上 派生
时,如果两个实例是相同的变体并且所有字段都相等,则它们是相等的。
如何实现 PartialEq
?
一个域的示例实现,在该域中,即使两本书的 ISBN 匹配,即使格式不同,也将其视为同一本书:
enum BookFormat {
Paperback,
Hardback,
Ebook,
}
struct Book {
isbn: i32,
format: BookFormat,
}
impl PartialEq for Book {
fn eq(&self, other: &Self) -> bool {
self.isbn == other.isbn
}
}
let b1 = Book { isbn: 3, format: BookFormat::Paperback };
let b2 = Book { isbn: 3, format: BookFormat::Ebook };
let b3 = Book { isbn: 10, format: BookFormat::Paperback };
assert!(b1 == b2);
assert!(b1 != b3);
Run如何比较两种不同的类型?
您可以比较的类型由 PartialEq
的类型参数控制。
例如,让我们对之前的代码进行一些调整:
// 衍生工具 <BookFormat> == <BookFormat> 比较
#[derive(PartialEq)]
enum BookFormat {
Paperback,
Hardback,
Ebook,
}
struct Book {
isbn: i32,
format: BookFormat,
}
// 实现 <Book> == <BookFormat> 比较
impl PartialEq<BookFormat> for Book {
fn eq(&self, other: &BookFormat) -> bool {
self.format == *other
}
}
// 实现 <BookFormat> == <Book> 比较
impl PartialEq<Book> for BookFormat {
fn eq(&self, other: &Book) -> bool {
*self == other.format
}
}
let b1 = Book { isbn: 3, format: BookFormat::Paperback };
assert!(b1 == BookFormat::Paperback);
assert!(BookFormat::Ebook != b1);
Run通过将 impl PartialEq for Book
更改为 impl PartialEq<BookFormat> for Book
,我们可以将 BookFormat 和 Book 进行比较。
像上面这样的比较 (它忽略了结构体的某些字段) 可能很危险。这很容易导致意外违反部分对等关系的要求。
例如,如果我们保留了以上针对 BookFormat
的 PartialEq<Book>
的实现,并为 Book
添加了 PartialEq<Book>
的实现 (通过 #[derive]
或第一个示例中的手动实现),则结果将违反传递性:
#[derive(PartialEq)]
enum BookFormat {
Paperback,
Hardback,
Ebook,
}
#[derive(PartialEq)]
struct Book {
isbn: i32,
format: BookFormat,
}
impl PartialEq<BookFormat> for Book {
fn eq(&self, other: &BookFormat) -> bool {
self.format == *other
}
}
impl PartialEq<Book> for BookFormat {
fn eq(&self, other: &Book) -> bool {
*self == other.format
}
}
fn main() {
let b1 = Book { isbn: 1, format: BookFormat::Paperback };
let b2 = Book { isbn: 2, format: BookFormat::Paperback };
assert!(b1 == BookFormat::Paperback);
assert!(BookFormat::Paperback == b2);
// 以下应该通过传递性来保持,但不是。
assert!(b1 == b2); // <-- PANICS
}
RunExamples
let x: u32 = 0;
let y: u32 = 1;
assert_eq!(x == y, false);
assert_eq!(x.eq(&y), false);
RunRequired Methods§
Provided Methods§
Implementors§
impl PartialEq<AsciiChar> for AsciiChar
impl PartialEq<Infallible> for Infallible
impl PartialEq<Alignment> for core::fmt::Alignment
impl PartialEq<IpAddr> for IpAddr
impl PartialEq<IpAddr> for Ipv4Addr
impl PartialEq<IpAddr> for Ipv6Addr
impl PartialEq<Ipv6MulticastScope> for Ipv6MulticastScope
impl PartialEq<SocketAddr> for SocketAddr
impl PartialEq<FpCategory> for FpCategory
impl PartialEq<IntErrorKind> for IntErrorKind
impl PartialEq<Which> for Which
impl PartialEq<SearchStep> for SearchStep
impl PartialEq<Ordering> for core::sync::atomic::Ordering
impl PartialEq<Ordering> for core::cmp::Ordering
impl PartialEq<bool> for bool
impl PartialEq<char> for char
impl PartialEq<f32> for f32
impl PartialEq<f64> for f64
impl PartialEq<i8> for i8
impl PartialEq<i16> for i16
impl PartialEq<i32> for i32
impl PartialEq<i64> for i64
impl PartialEq<i128> for i128
impl PartialEq<isize> for isize
impl PartialEq<!> for !
impl PartialEq<str> for str
impl PartialEq<u8> for u8
impl PartialEq<u16> for u16
impl PartialEq<u32> for u32
impl PartialEq<u64> for u64
impl PartialEq<u128> for u128
impl PartialEq<()> for ()
impl PartialEq<usize> for usize
impl PartialEq<AllocError> for AllocError
impl PartialEq<Layout> for Layout
impl PartialEq<LayoutError> for LayoutError
impl PartialEq<TypeId> for TypeId
impl PartialEq<CpuidResult> for CpuidResult
impl PartialEq<CharTryFromError> for CharTryFromError
impl PartialEq<DecodeUtf16Error> for DecodeUtf16Error
impl PartialEq<ParseCharError> for ParseCharError
impl PartialEq<TryFromCharError> for TryFromCharError
impl PartialEq<CStr> for CStr
impl PartialEq<FromBytesUntilNulError> for FromBytesUntilNulError
impl PartialEq<FromBytesWithNulError> for FromBytesWithNulError
impl PartialEq<Error> for Error
impl PartialEq<PhantomPinned> for PhantomPinned
impl PartialEq<Assume> for Assume
impl PartialEq<AddrParseError> for AddrParseError
impl PartialEq<Ipv4Addr> for IpAddr
impl PartialEq<Ipv4Addr> for Ipv4Addr
impl PartialEq<Ipv6Addr> for IpAddr
impl PartialEq<Ipv6Addr> for Ipv6Addr
impl PartialEq<SocketAddrV4> for SocketAddrV4
impl PartialEq<SocketAddrV6> for SocketAddrV6
impl PartialEq<NonZeroI8> for NonZeroI8
impl PartialEq<NonZeroI16> for NonZeroI16
impl PartialEq<NonZeroI32> for NonZeroI32
impl PartialEq<NonZeroI64> for NonZeroI64
impl PartialEq<NonZeroI128> for NonZeroI128
impl PartialEq<NonZeroIsize> for NonZeroIsize
impl PartialEq<NonZeroU8> for NonZeroU8
impl PartialEq<NonZeroU16> for NonZeroU16
impl PartialEq<NonZeroU32> for NonZeroU32
impl PartialEq<NonZeroU64> for NonZeroU64
impl PartialEq<NonZeroU128> for NonZeroU128
impl PartialEq<NonZeroUsize> for NonZeroUsize
impl PartialEq<ParseFloatError> for ParseFloatError
impl PartialEq<ParseIntError> for ParseIntError
impl PartialEq<TryFromIntError> for TryFromIntError
impl PartialEq<RangeFull> for RangeFull
impl PartialEq<Alignment> for core::ptr::Alignment
impl PartialEq<ParseBoolError> for ParseBoolError
impl PartialEq<Utf8Error> for Utf8Error
impl PartialEq<RawWaker> for RawWaker
impl PartialEq<RawWakerVTable> for RawWakerVTable
impl PartialEq<Duration> for Duration
impl PartialEq<TryFromFloatSecsError> for TryFromFloatSecsError
impl<'a> PartialEq<Location<'a>> for Location<'a>
impl<'a> PartialEq<Utf8Chunk<'a>> for Utf8Chunk<'a>
impl<A, B> PartialEq<[B]> for [A]where A: PartialEq<B>,
impl<A, B, const N: usize> PartialEq<&[B]> for [A; N]where A: PartialEq<B>,
impl<A, B, const N: usize> PartialEq<&mut [B]> for [A; N]where A: PartialEq<B>,
impl<A, B, const N: usize> PartialEq<[A; N]> for &[B]where B: PartialEq<A>,
impl<A, B, const N: usize> PartialEq<[A; N]> for &mut [B]where B: PartialEq<A>,
impl<A, B, const N: usize> PartialEq<[A; N]> for [B]where B: PartialEq<A>,
impl<A, B, const N: usize> PartialEq<[B; N]> for [A; N]where A: PartialEq<B>,
impl<A, B, const N: usize> PartialEq<[B]> for [A; N]where A: PartialEq<B>,
impl<A, B: ?Sized> PartialEq<&B> for &Awhere A: PartialEq<B> + ?Sized,
impl<A, B: ?Sized> PartialEq<&B> for &mut Awhere A: PartialEq<B> + ?Sized,
impl<A, B: ?Sized> PartialEq<&mut B> for &Awhere A: PartialEq<B> + ?Sized,
impl<A, B: ?Sized> PartialEq<&mut B> for &mut Awhere A: PartialEq<B> + ?Sized,
impl<B: PartialEq, C: PartialEq> PartialEq<ControlFlow<B, C>> for ControlFlow<B, C>
impl<Dyn: ?Sized> PartialEq<DynMetadata<Dyn>> for DynMetadata<Dyn>
impl<F: FnPtr> PartialEq<F> for F
impl<H> PartialEq<BuildHasherDefault<H>> for BuildHasherDefault<H>
impl<Idx: PartialEq> PartialEq<Range<Idx>> for Range<Idx>
impl<Idx: PartialEq> PartialEq<RangeFrom<Idx>> for RangeFrom<Idx>
impl<Idx: PartialEq> PartialEq<RangeInclusive<Idx>> for RangeInclusive<Idx>
impl<Idx: PartialEq> PartialEq<RangeTo<Idx>> for RangeTo<Idx>
impl<Idx: PartialEq> PartialEq<RangeToInclusive<Idx>> for RangeToInclusive<Idx>
impl<P: Deref, Q: Deref> PartialEq<Pin<Q>> for Pin<P>where P::Target: PartialEq<Q::Target>,
impl<T> PartialEq<(T,)> for (T₁, T₂, …, Tₙ)where T: ?Sized + PartialEq,
This trait is implemented for tuples up to twelve items long.