Consider the fact that the following code compiles and runs successfully:
println!("{}", std::mem::size_of::<Vec<i32>>()); // 24
println!("{}", std::mem::size_of::<Vec<char>>()); // 24
println!("{}", std::mem::size_of::<Vec<&str>>()); // 24
println!("{}", std::mem::size_of::<Box<i32>>()); // 8
println!("{}", std::mem::size_of::<Box<char>>()); // 8
println!("{}", std::mem::size_of::<Box<[i32]>>()); // 16
println!("{}", std::mem::size_of::<&[i32]>()); // 16
println!("{}", std::mem::size_of::<*mut *const [i32]>()); // 8
Now consider the following code:
println!("{}", std::mem::size_of::<[i32]>());
This fails to compile with error E0277 complaining that the size of [i32]
is not known at compile time. I definitely see why this must be so, because [i32]
is a i32 slice (i.e. a ‘raw’ slice in the sense given here [1], not a pointer to a slice (e.g. &[i32]
), whose size is known at compile time (i.e. the size of a fat pointer = 2 * size_of(usize))).
But now consider the following code:
println!("{}", std::mem::size_of::<Vec<[i32]>>());
When you try to compile this code, you also get error E0277, complaining that the size of Vec<[i32]>
is not known at compile time.
Why is this the case? Consider again these lines from above:
println!("{}", std::mem::size_of::<Vec<i32>>()); // 24
println!("{}", std::mem::size_of::<Vec<char>>()); // 24
println!("{}", std::mem::size_of::<Vec<&str>>()); // 24
We clearly see that the size of Vec<T>
is not dependent on the size of T, but is always the size a struct with 3 fields — pointer to data (8), length (8), capacity (8) — hence, 24.
So why does std::mem::size_of::<Vec<[i32]>>()
not simply return 24, but instead fail to compile?
I know that Vec<T>
requires T to implement Sized, and that that’s the immediate reason. But I guess I’m more wondering about the deeper reason behind the design decision to make it the case that Vec<T>
requires T to implement Sized.
Thanks!
[1] https://doc.rust-lang.org/reference/type-layout.html#slice-layout