Why do I get `trait bound [T]: std :: marker :: Sized` fails when I try to implement Ord and Eq manually on non-standard types?

When creating a structure that stores DST (for example, a raw slice), I can use the usual environment #[derive(Eq, PartialEq, Ord, PartialOrd)] to get implementations of this attribute by my type:

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

However, if I implement them manually, then the compiler will complain that my type does not implement 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() } } 

Compiler Result:

 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` 

If I create a variant of a type that has a fixed size (for example, turning it into a fixed size array), I can manually implement the traits without any problems.

 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 link to a playground showing the problem .

My question is: how to implement Ord and Eq in my custom DST so that I can take advantage of the fact that I can partial_cmp/eq any AsRef<[u8]> , but also use this to force the border to implement traits of Ord / Eq , like in struct B in my example?

+7
traits rust
source share
1 answer

The problem is that S: AsRef<[u8]> also restricts S types to Sized by default. You must use ?Sized to discard this.

All parameters of a type type implicitly have a Sized binding, so ?Sized can be used to discard an implicit binding.

From the book of Rust .

The following compilations are great for me:

 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 version

+7
source share

All Articles