Sized
The Sized trait in std::marker is a compiler marker trait implemented automatically for every type whose size in bytes is known at compile time.
Sized vs. Dynamically Sized Types (DSTs)
Local variables, function arguments, and return values must have a known size at compile time so the compiler can lay out stack frames. Types whose size is only known at runtime are called Dynamically Sized Types (DSTs) and do not implement Sized.
| Category | Examples | Sized? |
Pointer Representation (&T / Box<T>) |
|---|---|---|---|
| Scalars, structs, enums, arrays | i32, String, [u8; 16] |
Yes | Thin pointer (1 word: address) |
| Slices and string slices | [T], str, Path, OsStr |
No | Fat pointer (2 words: address + length) |
| Trait objects | dyn Display, dyn Error |
No | Fat pointer (2 words: data address + vtable address) |
Because DSTs do not implement Sized, they can only be manipulated behind a pointer or reference (&str, &[T], Box<dyn Error>, Arc<[u8]>).
Thin Pointer (&i32) Fat Pointer (&[i32] or &str)
+-------------------+ +-------------------+
| data_ptr (8 B) | | data_ptr (8 B) |
+-------------------+ | len (8 B) |
+-------------------+
Implicit T: Sized Bound and ?Sized Relaxation
Every generic type parameter T in Rust has an implicit T: Sized bound by default:
// Writing this:
fn inspect<T>(value: &T) {}
// Is desugared by the compiler to:
fn inspect<T: Sized>(value: &T) {}
To allow a generic function or struct to accept both Sized types and Dynamically Sized Types (behind a reference or smart pointer), opt out of the implicit Sized bound using the ?Sized ("maybe sized") syntax:
use std::fmt::Debug;
// Accepts both &Sized types (e.g. &Vec<i32>) and &DSTs (e.g. &str, &[i32]):
fn print_debug<T: Debug + ?Sized>(value: &T) {
println!("{value:?}");
}
fn main() {
let slice: &[i32] = &[1, 2, 3];
let text: &str = "unsized str slice";
let number: i32 = 99;
print_debug(slice); // T = [i32] (!Sized)
print_debug(text); // T = str (!Sized)
print_debug(&number); // T = i32 (Sized)
}
[1, 2, 3]
"unsized str slice"
99
Without + ?Sized, passing slice (where T = [i32]) or text (where T = str) fails with error[E0277]: the size for values of type 'str' cannot be known at compilation time.