In this lesson, you will learn how to write generic wrappers that can safely hold Dynamically Sized Types (DSTs) by using Rust’s special unsized trait bounds.
Understanding the "Unsized" Problem
In Rust, most types have a size known at compile time. However, some types, like slices ([T]) or trait objects (dyn Trait), do not. We call these Dynamically Sized Types (DSTs). By default, when you define a generic struct like struct Wrapper<T> { value: T }, Rust implicitly adds a Sized bound to T. This means Wrapper<[u8]> is rejected because the compiler doesn't know how much space to allocate for the slice inside the struct.
Relaxing the Constraint with ?Sized
To allow a generic type to hold a DST, we must explicitly "opt-out" of the default Sized requirement using the ?Sized syntax. This tells the compiler: "It is okay if the size of T is unknown at compile time."
Here is how you can define a container that handles both sized and unsized types:
struct Wrapper<T: ?Sized> {
value: T,
}
fn main() {
// This works! A simple integer has a known size.
let sized_wrap = Wrapper { value: 42 };
// This also works! [u8; 3] is a DST when viewed as [u8].
// We usually interact with these via pointers, like Box<Wrapper<[u8]>>.
let unsized_wrap: Box<Wrapper<[u8]>> = Box::new(Wrapper { value: [1, 2, 3] });
}
Why This Matters for Generics
When you use ?Sized, you take on the responsibility of managing the memory. Because the compiler doesn't know the size, you cannot store the value directly on the stack as a local variable; it wouldn't know how much stack space to reserve. Instead, you typically store the Wrapper<T> behind a pointer, such as a Box<T>, &T, or Rc<T>.
By removing the Sized bound, your generic code becomes significantly more flexible, allowing your abstractions to operate on slices or trait objects just as easily as they operate on fixed-size types like i32 or String.
Key Takeaway: Use the ?Sized trait bound to allow your generic types to accept unsized types, but remember that you must store these types behind a pointer since their exact size is unknown at compile time.