请将此视为原回答的补充内容,该回答适用于您特定情况。本回答涉及您问题的第二部分。
考虑以下结构:
struct Person {
id: u32,
name: String,
height: u32,
}
平等性: PartialEq
和 Eq
特质
PartialEq
特质,摘自文档
Trait for equality comparisons which are partial equivalence
relations. This trait allows for partial equality, for types that do not
have a full equivalence relation. For example, in floating point numbers
NaN != NaN, so floating point types implement PartialEq but not Eq.
Formally, the equality must be (for all a, b and c):
symmetric: a == b implies b == a; and
transitive: a == b and b == c implies a == c.
如果你想表达你的类型的值相等的含义,你必须实现 PartialEq
特质。实现它允许我们为我们的类型编写 x == y
和 x != y
。
impl PartialEq for Person {
fn eq(&self, other: &Person) -> bool {
self.height == other.height
}
}
请注意,我们仅根据身高来决定
Person
结构的相等性。如果您想比较每个结构字段,也可以实现此
eq
方法。
fn eq(&self, other: &Person) -> bool {
self.id == other.id && self.name == other.name && self.height == other.height
}
如果您想要这种行为,只需简单地添加 #[derive(PartialEq)]
即可更容易实现。
Eq Trait,来自文档
Trait for equality comparisons which are equivalence relations.
This means, that in addition to a == b and a != b being strict inverses,
the equality must be (for all a, b and c):
reflexive: a == a;
symmetric: a == b implies b == a; and
transitive: a == b and b == c implies a == c.
This property cannot be checked by the compiler, and therefore Eq implies
PartialEq, and has no extra methods.
Derivable
This trait can be used with #[derive]. When derived, because Eq has no extra methods,
it is only informing the compiler that this is an equivalence relation rather than a
partial equivalence relation. Note that the derive strategy requires all
fields are Eq, which isn't always desired.
PartialEq 是用于不一定自反的关系(即可能存在 x != x 的情况),而 Eq 是一个标记 trait,它表示该关系也是自反的(现在它是一个适当的等价关系)。
您还可以通过空 impl 块手动实现 Eq
trait。
impl Eq for Person {}
但是,将Eq
添加到您的#[derive(Eq)]
列表中会更容易。
顺序: PartialOrd
和Ord
traits
使用操作符<
、<=
、>=
和>
计算值之间的相对顺序。要为自己的类型实现这些操作,必须实现PartialOrd
特性。
在实现PartialOrd
之前,必须实现PartialEq
。
impl PartialOrd for Person {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
Ordering
是一个枚举类型,包含以下数值:
pub enum Ordering {
Less,
Equal,
Greater,
}
partial_cmp
返回一个 Option
而不是一个 Ordering
,因为有些类型的值不能总是进行比较,例如浮点数。 NaN
不是可表示的数字;表达式如 3.0 < NaN
没有任何意义。在这些情况下,partial_cmp
返回 None
。浮点数是标准库中唯一发生这种情况的情况。更多细节可以在这里找到。
partial_cmp
返回 Option<Ordering>
的事实意味着:可能无法确定地将两个值 x 和 y 放入一个确定的顺序中。在实践中,这意味着仅实现 PartialOrd
不足以使您的值可排序。您还需要实现 Ord
trait。
在实现 Ord
之前,必须先实现 PartialOrd
、Eq
和 PartialEq
。
对于我们的 Person
结构体,同样可以委托给我们的一个成员变量:
impl Ord for Person {
fn cmp(&self, other: &Person) -> Ordering {
self.height.cmp(&other.height)
}
}
Ord
应用于所有具有PartialOrd
的类型”,OP似乎不想要求PartialOrd
类型实现Ord
,只是希望对已经实现Ord
的类型提供一个默认实现以减少冗余。这完全合理和可行,但在目前的特质系统中不可能实现(但可能没有足够的好处以被包含在未来版本中)。 - user395760Ord
的东西都不能自动提供PartialOrd
?”这个问题。该问题仅要求在已经假定了Ord
的情况下自动提供PartialOrd
,但并非总是如此,如果不总是这样,那么“如果我们要求所有东西都是Ord
”从何而来?听起来相当混乱。 - oblitumcmp
,也不实现partial_cmp
?如果没有,那么手动编写两者具有相同样板代码似乎是语言上的限制。 - oblitumOption
的包装,因为当您指定Ord
时,您意味着每个Option<Ordering>
都是Some
。 - TSK