首页 文章

为什么我得到一个`trait bound` [T]:当我尝试在unsized类型上手动实现Ord和Eq时,不满足std :: marker :: Sized`?

提问于
浏览
7

在创建存储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上实现 OrdEq ,以便我可以利用任何 AsRef<[u8]> 的事实 partial_cmp/eq ,但也可以使用它来强制执行 Ord / Eq trait实现的边界,如在我的例子中我用 struct B 做什么?

1 回答

  • 7

    问题是 S: AsRef<[u8]> 默认情况下也将 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

相关问题