Rust 为一个类型实现Ord很尴尬吗?
我有一个新类型,我想实现Rust 为一个类型实现Ord很尴尬吗?,rust,traits,ord,Rust,Traits,Ord,我有一个新类型,我想实现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)
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)
}
}
pub trait Ord: Eq + PartialOrd<Self>
当我尝试比较我的类型的两个变量时,会出现错误:
error[E0277]:不满足特性绑定'MyType:std::cmp::PartialOrd'
-->src/main.rs:5:6
|
5 | MyType的impl命令{
|^^^无法将'MyType'与'MyType'进行比较`
|
=help:trait`std::cmp::PartialOrd`未为`MyType'实现`
错误[E0277]:未满足特性绑定'MyType:std::cmp::Eq'
-->src/main.rs:5:6
|
5 | MyType的impl命令{
|^MyType未实现特性'std::cmp::Eq'`
当我实现PartialEq
,Eq
和PartialOrd
(gt()
,lt()
,Eq()
,ge()
,le()
等)时,一切正常,但如果我提供cmp
,我们可以推断出lt()
和Eq()等函数
!这是多余的!我不喜欢这样
在查看时,我在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)
}
}
pub trait Ord: Eq + PartialOrd<Self>
Ord:Eq+PartialOrd
这看起来像是trait从Eq
和PartialOrd
继承而来。为什么trait不能使用cmp
函数为继承的trait提供所需方法的默认实现?我不知道trait的继承是如何工作的,搜索结果没有任何用处,但我认为这是一个值得关注的问题应该是可能的
Rust是如何实现的?我希望不是这样…对于初学者,您只能实现
PartialOrd::partial\u cmp
,如lt
、le
、gt
、和ge
等默认实现。此外,如果您实现Ord
,您可以像往常一样简单地实现cmp
,并且partial_cmp
变成了一些(self.cmp(other))
但是,如果您只想委托给某个字段的相等和排序概念,那么派生出来就更好、更容易了:
#[derive(PartialOrd, Ord, PartialEq, Eq)]
struct MyType(isize);
对于您的具体情况,我将使用
#[派生]
:
#[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))
}
如果你需要对你的Ord
实现进行特殊处理,你仍然需要写出那些代码,没有什么可以帮我们做到这一点!你仍然可以为其他特性派生实现,如果这样做有意义的话
你问题的另一部分模棱两可,因此我将从两个方面回答:
为什么使用PartialOrd
的任何东西都不能自动提供Ord
让我们看一下和的文档
PartialOrd
说:“比较必须满足和”,而Ord
说:“形成a的类型”。这些是数学术语,我不会像维基百科那样描述它们
但是,我们可以以浮点数为例。浮点数有一个名为NaN
的特殊值。与此值进行比较是很棘手的。例如,所有1.0
、1.0==NaN
和1.0>NaN
都是false!它们不构成总顺序,但我们仍然可以将一个值与另一个值进行比较。这这就是PartialOrd
存在的原因-允许我们比较类似的类型。顺便说一句,PartialEq
存在的原因类似
我们不能用PartialOrd
来定义Ord
,因为我们对底层类型没有适当的保证。这是Rust的类型系统,避免了我们犯错误
为什么使用Ord
的任何东西都不能自动提供PartialOrd
这里的问题是PartialOrd
类型比Ord
类型多。如果我们要求所有类型都是Ord
,那么我们就不能进行任何浮点比较,因为它们没有总顺序,否则我们就不得不放弃总顺序,失去它提供的安全性
然而,对于派生
,已经有了自动执行此操作的想法。建议将上述代码缩减为:
#[derive(Debug, Copy, Eq, Ord)]
struct MyType(isize);
当我实现PartialOrd
(gt()
,lt()
,eq()
,ge()
,le()
)
<> >注意<代码> PARTALORD 确实有缺省实现,您只需要实现<代码> PIDALLY-CMP 。其他都是为了方便使用或可能性能原因。请将此作为原始答案的补充,适合您的具体情况。此答案涉及到您的第二部分。问题 考虑这个结构:
struct Person {
id: u32,
name: String,
height: u32,
}
平等性:PartialEq
和Eq
特征
来自文档的PartialEq Trait
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是否相等。如果要比较每个结构体字段,您也可以实现此eq
方法:
fn eq(&self, other: &Person) -> bool {
self.id == other.id && self.name == other.name && self.height == other.height
}
但是,如果您希望这样做,只需添加#[派生(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!=x),Eq是一个标记特征,表示关系也是自反的(现在它是一个适当的等价关系)
您还可以使用空impl块手动实现Eq
trait
impl Eq for Person {}
但是,同样,将Eq
添加到#[导出(Eq)]
列表中更容易
排序:特征的PartialOrd
和Ord
traits
值的相对顺序是使用操作符
计算的。要为您自己的应用程序实现这些操作,请
impl Ord for Person {
fn cmp(&self, other: &Person) -> Ordering {
self.height.cmp(&other.height)
}
}