我有一个newtype,我想实现Ord
:
use std::cmp::{Ord, Ordering};
struct MyType(isize);
impl Ord for MyType {
fn cmp(&self, &other: Self) -> Ordering {
let MyType(ref lhs) = *self;
let MyType(ref rhs) = *other;
lhs.cmp(rhs)
}
}
Run Code Online (Sandbox Code Playgroud)
当我尝试比较我的类型的两个变量时,我得到错误:
error[E0277]: the trait bound `MyType: std::cmp::PartialOrd` is not satisfied
--> src/main.rs:5:6
|
5 | impl Ord for MyType {
| ^^^ can't compare `MyType` with `MyType`
|
= help: the trait `std::cmp::PartialOrd` is not implemented for `MyType`
error[E0277]: the trait bound `MyType: std::cmp::Eq` is not satisfied
--> src/main.rs:5:6
|
5 | impl Ord for MyType {
| ^^^ the trait `std::cmp::Eq` is not implemented for `MyType`
Run Code Online (Sandbox Code Playgroud)
当我执行PartialEq
,Eq
和PartialOrd
(gt()
,lt()
,eq()
,ge()
,le()
,等),一切工作正常,但如果我提供的cmp
,我们可以推断出类似的功能lt()
和eq()
!这是多余的!我不喜欢这个!
查看文档时,我在以下定义中看到了这一点Ord
:
pub trait Ord: Eq + PartialOrd<Self>
Run Code Online (Sandbox Code Playgroud)
这看起来像trait继承自Eq
和PartialOrd
.为什么特征不能使用该cmp
函数从继承的特征中为所需方法提供默认实现?我不知道traits的继承是如何起作用的,而且搜索没有任何用处,但我认为这是应该可行的.
怎么在Rust中完成?我希望不是这样的......
She*_*ter 10
对于您的具体情况,我会使用#[derive]
:
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
struct MyType(isize);
fn main() {
let a = MyType(5);
let b = MyType(6);
println!("{:?}", a.cmp(&b))
}
Run Code Online (Sandbox Code Playgroud)
如果你需要特殊情况你的Ord
实现,你仍然必须写出代码,没有什么可以拯救我们!如果有意义的话,您仍然可以派生其他特征的实现.
你问题的另一部分含糊不清,所以我会以两种方式回答它:
为什么不能通过
Ord
任何东西自动提供PartialOrd
?
让我们来看看文档的PartialOrd
和Ord
.
PartialOrd
他说:"比较必须满足反对称性和传递性 ",同时Ord
说:"形成总秩序的类型".这些都是数学术语,我不会像维基百科那样描述它们.
但是,我们可以使用浮点数作为示例.浮点数具有特殊值NaN
.与这个值相比是很棘手的.例如,所有的1.0 < NaN
,1.0 == NaN
并且1.0 > NaN
都是假的!这些不构成总订单,但我们仍然可以将一个值与另一个值进行比较.这就是PartialOrd
存在的原因- 允许我们比较这样的类型.顺便说一下,PartialEq
出于类似的原因存在.
我们无法定义Ord
,PartialOrd
因为我们没有对基础类型的适当保证.这是Rust的类型系统,使我们免于犯错误!
为什么不能通过
PartialOrd
任何东西自动提供Ord
?
这里的问题是PartialOrd
比他们更多的类型Ord
.如果我们需要一切Ord
,那么我们就不能进行任何浮点比较,因为它们没有总订单,或者我们不得不放弃总订单而失去它提供的安全性.
但是,有一些想法可以自动执行此操作derive
.建议的RFC 2385允许将上述代码简化为:
#[derive(Debug, Copy, Eq, Ord)]
struct MyType(isize);
Run Code Online (Sandbox Code Playgroud)
当我执行
PartialOrd
(gt()
,lt()
,eq()
,ge()
,le()
...)
请注意,PartialOrd
确实有默认实现,您只需要实现cmp
.其他的是易于使用或可能的性能原因.
Gra*_*Dot 10
请将此视为原始答案的附录,适合您的具体情况。这个答案涉及您问题的第二部分。
\n\n考虑这个结构:
\n\nstruct Person {\n id: u32,\n name: String,\n height: u32,\n}\n
Run Code Online (Sandbox Code Playgroud)\n\nPartialEq
和Eq
特征PartialEq Trait,来自文档
\n\nTrait for equality comparisons which are partial equivalence \nrelations. This trait allows for partial equality, for types that do not\nhave a full equivalence relation. For example, in floating point numbers\nNaN != NaN, so floating point types implement PartialEq but not Eq.\n\nFormally, the equality must be (for all a, b and c):\n\nsymmetric: a == b implies b == a; and\ntransitive: a == b and b == c implies a == c.\n
Run Code Online (Sandbox Code Playgroud)\n\n因此,如果您想表达类型值相等的含义,则必须实现该PartialEq
特征。实现它允许我们为我们的类型编写x == y
和x != y
。
impl PartialEq for Person {\n fn eq(&self, other: &Person) -> bool {\n self.height == other.height\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n请注意,我们Person
只是根据高度来决定结构的相等性。eq
如果您想比较每个结构体字段,您也可以实现此方法:
fn eq(&self, other: &Person) -> bool {\n self.id == other.id && self.name == other.name && self.height == other.height\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n#[derive(PartialEq)]
但如果这是您想要的行为,那么简单地添加会更容易。
Eq Trait,来自文档
\n\nTrait for equality comparisons which are equivalence relations.\n\nThis means, that in addition to a == b and a != b being strict inverses, \nthe equality must be (for all a, b and c):\n\nreflexive: a == a;\nsymmetric: a == b implies b == a; and\ntransitive: a == b and b == c implies a == c.\n\nThis property cannot be checked by the compiler, and therefore Eq implies\nPartialEq, and has no extra methods.\n\nDerivable\nThis trait can be used with #[derive]. When derived, because Eq has no extra methods, \nit is only informing the compiler that this is an equivalence relation rather than a \npartial equivalence relation. Note that the derive strategy requires all \nfields are Eq, which isn\'t always desired.\n
Run Code Online (Sandbox Code Playgroud)\n\nPartialEq 适用于不一定是自反的关系(即可以存在 x != x 的 x),并且 Eq 是一个标记特征,表明该关系也是自反的(现在它是一个正确的等价关系)。
\n\n您还可以Eq
使用空的 impl 块手动实现该特征
impl Eq for Person {}\n
Run Code Online (Sandbox Code Playgroud)\n\nEq
但是,再次强调,将其添加到您的列表中更容易#[derive(Eq)]
。
PartialOrd
和Ord
特征值的相对顺序是使用运算符<
、<=
和计算>=
的>
。要为您自己的类型实现这些,您必须实现该PartialOrd
特征。
在你能够实施之前PartialOrd
,你必须先实施PartialEq
。
impl PartialOrd for Person {\n fn partial_cmp(&self, other: &Self) -> Option<Ordering> {\n Some(self.cmp(other)) \n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\nOrdering
是一个具有以下值的枚举:
pub enum Ordering {\n Less,\n Equal,\n Greater,\n}\n
Run Code Online (Sandbox Code Playgroud)\n\npartial_cmp
返回 anOption
而不是 an Ordering
,因为有些类型的值不能总是进行比较,例如浮点数。NaN
s 是不可表示的数字;诸如3.0 < NaN
don\xe2\x80\x99t 之类的表达式是有意义的。在这些情况下,partial_cmp
返回None
. 浮点值是标准库中唯一发生这种情况的情况。可以在这里找到更多内容。
partial_cmp
返回 an的事实Option<Ordering>
会产生一个后果:可能无法将两个值 x 和 y 按确定的顺序放置。实际上,这意味着实施PartialOrd
不足以使您的值可排序。您还需要实施Ord
特征。
在实施之前Ord
,您必须首先实施PartialOrd
,Eq
和PartialEq
。
对于我们的Person
结构体,我们可以再次委托给我们的成员变量之一:
impl Ord for Person {\n fn cmp(&self, other: &Person) -> Ordering {\n self.height.cmp(&other.height)\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
小智 6
对于初学者来说,你只能实现PartialOrd::partial_cmp
,因为lt
,le
,gt
,和ge
有缺省的实现.此外,如果你实施Ord
,你可以cmp
像往常一样简单地实现并partial_cmp
变得公正Some(self.cmp(other))
.
但是,如果您只想委托某个字段的相等和排序概念,那么派生它会更好更容易:
#[derive(PartialOrd, Ord, PartialEq, Eq)]
struct MyType(isize);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2258 次 |
最近记录: |