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
Sized
bound 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
Sized
to 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