为类型实现Ord很尴尬?

时间:2015-02-07 21:40:35

标签: 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)
    }
}

当我尝试比较我的类型的两个变量时,我会收到错误:

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`

当我实施PartialEqEqPartialOrdgt()lt()eq()ge(),{{ 1}}等等,一切正常,但如果我提供le(),我们可以推断cmplt()等函数!这是多余的!我不喜欢这个!

在查看the docs时,我在eq()

的定义中看到了这一点
Ord

这似乎是从pub trait Ord: Eq + PartialOrd<Self> Eq继承的特征。为什么特征不能使用PartialOrd函数从继承的特征中为所需方法提供默认实现?我不知道特征的继承是如何起作用的,而且搜索没有任何用处,但我认为这是应该可行的。

在Rust中如何完成?我希望不是这样......

2 个答案:

答案 0 :(得分:9)

对于您的具体情况,我使用#[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))
}

如果您需要特殊情况Ord实施,您仍然需要写出该代码,没有任何可以拯救我们的东西!如果有意义的话,你仍然可以推导出其他特征的实现。

你问题的另一部分含糊不清,所以我会以两种方式回答它:

  

为什么Ord可以自动提供PartialOrd

让我们看一下PartialOrdOrd的文档。

PartialOrd说:&#34;比较必须满足antisymmetrytransitivity&#34;,而Ord说:&#34;类型形成一个total order&#34 ;.这些都是数学术语,我不会像维基百科所描述的那样做得好。

但是,我们可以使用浮点数作为示例。浮点数具有一个名为NaN的特殊值。与这个值相比是很棘手的。例如,1.0 < NaN1.0 == NaN1.0 > NaN都是假的!这些不构成总订单,但我们仍然可以将一个值与另一个值进行比较。这就是PartialOrd存在的原因 - 允许我们比较这样的类型。顺便说一下,PartialEq出于类似的原因存在。

我们无法用Ord来定义PartialOrd,因为我们对基础类型没有适当的保证。这是Rust的类型系统,可以避免我们犯错!

  

为什么PartialOrd可以自动提供Ord

这里的问题是PartialOrd种类型多于OrdOrd。如果我们要求所有内容都是derive,那么我们就无法进行任何浮点比较,因为它们没有总订单,或者我们没有必须放弃总订单并失去它提供的安全性。

但是,有一些想法会自动为#[derive(Debug, Copy, Eq, Ord)] struct MyType(isize); 执行此操作。建议的RFC 2385允许将上述代码简化为:

PartialOrd
  

当我实施gt()lt()eq()ge()le()PartialOrd ...)

请注意,cmp 具有默认实现,您只需要实现{{1}}。其他的是易于使用或可能是性能原因。

答案 1 :(得分:6)

对于初学者,您只能实施PartialOrd::partial_cmpltlegtge都有默认实施。此外,如果您实施Ord,则可以像往常一样实施cmppartial_cmp变为Some(self.cmp(other))

但是,如果您只想委托某个领域的平等和排序概念,那么它的推导会更好,更容易:

#[derive(PartialOrd, Ord, PartialEq, Eq)]
struct MyType(isize);