In Rust, "sized types" are types whose size is known at compile-time, such as ‘i32‘, ‘bool‘, or any fixed-size array. However, Rust also has "unsized types" or "dynamically sized types" where the size of the type is not known until runtime, such as a string (‘String‘), an array of unknown length (‘[T]‘), or a trait object (‘dyn Trait‘).
An important aspect of unsized types in Rust is that they are only allowed in certain contexts, such as function arguments, return values, and certain struct and enum fields. This is because the size of these types is usually determined at runtime, and the Rust type system requires that types have a known and fixed size at compile time to ensure safe memory management.
To make this work, Rust has two traits to differentiate between sized and unsized types: ‘Sized‘ and ‘Unsized‘. The ‘Sized‘ trait is automatically implemented for all sized types, while the ‘Unsized‘ trait is automatically implemented for all unsized types. Additionally, Rust has a third trait called ‘DynamicallySized‘, which is implemented for types that are unsized and not controlled by ‘Sized‘ or ‘Unsized‘ markers.
To pass an unsized type as a parameter to a function, Rust requires that you wrap it using a reference ‘&‘, a mutable reference ‘&mut‘, or a box ‘Box‘. For example, to pass an unsized string to a function, you would use a reference like so:
fn print_string(s: &str) {
println!("{}", s);
}
fn main() {
let a = "hello";
let b = String::from("world");
print_string(a);
print_string(&b);
}
In this example, ‘a‘ is a string literal and ‘b‘ is a dynamically allocated string, but both can be passed as references to the ‘print_string‘ function because the ‘str‘ type is an unsized type and can be wrapped in a reference.
Overall, unsized types and the traits ‘Sized‘, ‘Unsized‘, and ‘DynamicallySized‘ are an important part of Rust’s type system and allow for the safe use of dynamically sized types at runtime.