The Rust Book gives an example of the Sized trait:
fn generic<T: ?Sized>(t: &T) {}
But what's the point of this? You already have to put DSTs behind references by default, so why add this extra syntax? Something like
fn generic(t: T) {}
is already callable with &str, &[T], etc.
Taking a sized T
by value is not the same as taking a reference to a potentially unsized T
. Note that references are their own distinct concrete types, and not just a passing convention or whatnot. Moreover, other types support unsized generics, like Box<_>
for instance.
Here's a quick demonstration.
trait Trait {}
impl Trait for str {}
impl Trait for () {}
// This works
fn example<T: ?Sized + Trait>(_shared_ref: &T) {}
// These don't
// fn example<T: Trait>(_owned_t: T) {}
// fn example<T: Trait>(_shared_ref_to_sized_t: &T) {}
fn main() {
example("");
example(&() as &dyn Trait);
}
4 Likes
fn generic<T: ?Sized>(t: &T) {}
This code can only accept references. For example, you can't make it consume a Vec<i32>
. Compared to the code that just accepts a t: T
, the above code is more restrictive in what it can accept. This can be done if the function body can only handle references and nothing else.
2 Likes