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)
    }
}