Unsized Types

Most types have a particular size, in bytes, that is knowable at compile time. For example, an i32`i32is thirty-two bits big, or four bytes. However, there are some types which are useful to express, but do not have a defined size. These are called ‘unsized’ or ‘dynamically sized’ types. One example is` is thirty-two bits big, or four bytes. However, there are some types which are useful to express, but do not have a defined size. These are called ‘unsized’ or ‘dynamically sized’ types. One example is [T]`[T]. This type represents a certain number of`. This type represents a certain number of T`T` in sequence. But we don’t know how many there are, so the size is not known.

Rust understands a few of these types, but they have some restrictions. There are three:

  1. We can only manipulate an instance of an unsized type via a pointer. An &[T]`&[T]works just fine, but a` works just fine, but a [T]`[T]` does not.
  2. Variables and arguments cannot have dynamically sized types.
  3. Only the last field in a struct`struct` may have a dynamically sized type; the other fields must not. Enum variants must not have dynamically sized types as data.

So why bother? Well, because [T]`[T]` can only be used behind a pointer, if we didn’t have language support for unsized types, it would be impossible to write this:

fn main() { impl Foo for str { }
impl Foo for str {

or

fn main() { impl<T> Foo for [T] { }
impl<T> Foo for [T] {

Instead, you would have to write:

fn main() { impl Foo for &str { }
impl Foo for &str {

Meaning, this implementation would only work for references, and not other types of pointers. With the impl for str`impl for str, all pointers, including (at some point, there are some bugs to fix first) user-defined custom smart pointers, can use this`, all pointers, including (at some point, there are some bugs to fix first) user-defined custom smart pointers, can use this impl`impl`.

?Sized

If you want to write a function that accepts a dynamically sized type, you can use the special bound, ?Sized`?Sized`:

fn main() { struct Foo<T: ?Sized> { f: T, } }
struct Foo<T: ?Sized> {
    f: T,
}

This ?`?, read as “T may be`, read as “T may be Sized`Sized”, means that this bound is special: it lets us match more kinds, not less. It’s almost like every`”, means that this bound is special: it lets us match more kinds, not less. It’s almost like every T`Timplicitly has` implicitly has T: Sized`T: Sized, and the`, and the ?`?` undoes this default.