【问题标题】:Why do I get a `trait bound `[T]: std::marker::Sized` is not satisfied when I try and implement Ord and Eq manually on unsized types?当我尝试在未调整大小的类型上手动实现 Ord 和 Eq 时,为什么我得到一个 `trait bound `[T]: std::marker::Sized` 不满意?
【发布时间】:2016-10-13 22:48:37
【问题描述】:

在创建存储 DST(例如,原始切片)的结构时,我可以使用普通的 #[derive(Eq, PartialEq, Ord, PartialOrd)] 工具在我的类型上实现此特征:

#[derive(PartialEq, Eq, PartialOrd, Ord)]
struct A([u8]);

但是,如果我手动实现它们,那么编译器会抱怨我的类型没有实现Sized:

struct A([u8]);

impl AsRef<[u8]> for A {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

impl<S: AsRef<[u8]>> PartialEq<S> for A {
    fn eq(&self, other: &S) -> bool {
        self.0.eq(other.as_ref())
    }
}

impl Eq for A { }

impl<S: AsRef<[u8]>> PartialOrd<S> for A {
    fn partial_cmp(&self, other: &S) -> Option<Ordering> {
        let  slice: &[u8] = &self.0;
        slice.partial_cmp(other.as_ref())
    }
}

impl Ord for A {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(&other).unwrap()
    }
}

编译结果:

rustc 1.12.0 (3191fbae9 2016-09-23)
error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied
  --> <anon>:20:6
   |
20 | impl Eq for A { }
   |      ^^
   |
   = note: `[u8]` does not have a constant size known at compile-time
   = note: required because it appears within the type `A`
   = note: required because of the requirements on the impl of `std::cmp::PartialEq` for `A`
   = note: required by `std::cmp::Eq`

error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied
  --> <anon>:29:6
   |
29 | impl Ord for A {
   |      ^^^
   |
   = note: `[u8]` does not have a constant size known at compile-time
   = note: required because it appears within the type `A`
   = note: required because of the requirements on the impl of `std::cmp::PartialOrd` for `A`
   = note: required by `std::cmp::Ord`

如果我创建一个 确实 具有固定大小的类型的变体(例如,通过将其转换为固定大小的数组),那么我可以手动实现特征没有问题。

struct B([u8; 5]);

impl AsRef<[u8]> for B {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

impl<S: AsRef<[u8]>> PartialEq<S> for B {
    fn eq(&self, other: &S) -> bool {
        self.0.eq(other.as_ref())
    }
}

impl Eq for B { }

impl<S: AsRef<[u8]>> PartialOrd<S> for B {
    fn partial_cmp(&self, other: &S) -> Option<Ordering> {
        let  slice: &[u8] = &self.0;
        slice.partial_cmp(other.as_ref())
    }
}

impl Ord for B {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(&other).unwrap()
    }
}

Here is a playground link showing the issue.

我的问题是 - 我如何在我的自定义 DST 上实现 Ord 和 Eq,这样我就可以利用我可以通过任何 AsRef&lt;[u8]&gt; 进行 partial_cmp/eq 的事实,但也可以使用它来强制执行Ord/Eq 特征实现的边界,就像我在示例中对 struct B 所做的那样?

【问题讨论】:

  • @matthieuM.,PartialOrd 特征的定义需要PartialEq,所以根据我的理解,我认为#[derive(PartialOrd)] 也可以要求#[derive(PartialEq)]。
  • @MatthieuM。我不明白这有什么问题。 PartialOrd 需要 PartialEq。 struct A(u8); 也会发生同样的事情。
  • @Dogbert:我在某些时候得到了一些奇怪的东西......但我担心我后来减少了太多。

标签: rust traits


【解决方案1】:

问题是S: AsRef&lt;[u8]&gt; 默认情况下也将S 限制为Sized 类型。您需要使用?Sized 选择退出。

所有泛型类型参数都隐式地具有Sized 绑定,因此?Sized 可用于退出隐式绑定。

From the Rust Book.

以下编译对我来说很好:

use std::cmp::Ordering;

struct A([u8]);

impl AsRef<[u8]> for A {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

impl<S: AsRef<[u8]> + ?Sized> PartialEq<S> for A {
    fn eq(&self, other: &S) -> bool {
        self.0.eq(other.as_ref())
    }
}

impl Eq for A {}

impl<S: AsRef<[u8]> + ?Sized> PartialOrd<S> for A {
    fn partial_cmp(&self, other: &S) -> Option<Ordering> {
        let slice: &[u8] = &self.0;
        slice.partial_cmp(other.as_ref())
    }
}

impl Ord for A {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(&other).unwrap()
    }
}

Demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-29
    • 1970-01-01
    • 2020-10-22
    相关资源
    最近更新 更多