I defined a trait ReadTag which contains a function that returns Self but such yields an error:
trait ReadTag {
fn read_out(buf: &mut &[u8]) -> Option<Self>;
}
error[E0277]: the size for values of type `Self` cannot be known at compilation time
--> src/lib.rs:2:37
|
2 | fn read_out(buf: &mut &[u8]) -> Option<Self>;
| ^^^^^^^^^^^^ doesn't have a size known at compile-time
The error is fixed by adding Sized as a supertrait, which makes sense, but why isn't Sized the default like it is for functions?
fn my_sized<T>(t: T) { } // all good, Sized is opt-out :)
fn my_unsized<T: ?Sized>(t: T) { } // not allowed
The documentation on Sized covers why it is not a default/implicit bound on traits:
A trait does not have an implicit
Sizedbound as this is incompatible with trait objects where, by definition, the trait needs to work with all possible implementors, and thus could be any size.Although Rust will let you bind
Sizedto a trait, you won’t be able to use it to form a trait object later:trait Foo { } trait Bar: Sized { } struct Impl; impl Foo for Impl { } impl Bar for Impl { } let x: &dyn Foo = &Impl; // OK // let y: &dyn Bar = &Impl; // error: the trait `Bar` cannot // be made into an object
Disallowing dyn Trait by default does sound like a poor choice.
As for why Sized is the default on everything else (functions, structs, enums, types, etc,) requires more guesswork. Likely it is just more common to require Sized types in most other contexts and requiring T: Sized everywhere would be a noisy burden. The latter (of relaxing the constraint with T: ?Sized when unsized types are desired) is the least cumbersome of the two. Corroborated by this answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With