我们已经知道编译器对类型是有严格要求:编译时已知使用内存大小。
所以对于DST类型,编译器是不接受的,要让编译器接受DST类型,必须绕一个弯:借助胖指针(fat pointer)。
胖指针是指针类型的一种特殊指针:
- 指向静态sized类型值的常规指针;对于数组
[i32; 3]而言,& [i32; 3]就是常规指针; - 指向动态sized类型值的胖指针:使用的内存空间是常规指针所使用的内存空间的两倍,切片(
& [i32])这种指针是胖指针(fat pointer);trait对象和切片变量的类型其实是胖指针类型!
为什么Rust编译器会把 &[i32] 这种类型的指针当成胖指针处理呢?因为在Rust眼里,[i32]也是一个合理的类型。它代表由 i32 类型组成的数组,然而长度在编译阶段不确定。
Rust代码中不能直接声明一个变量的类型是 DST 类型,因为编译器没办法知道怎么为这种变量分配内存。
但是,指向DST类型的指针是可以存在的,因为指针的大小总是固定的。
Rust中有一个重要的 trait Sized,可以用于区分一个类型是不是 DST类型。
所有的 DST 类型都不受 Sized约束。
我们可以在泛型约束中使用 Sized、!Sized、?Sized 三种写法:
T:Sized代表类型必须是编译期确定大小的,T:!Sized 代表类型必须是编译期不确定大小的,
T:?Sized 代表以上两种情况都可以。
在泛型代码中,泛型类型参数默认受 Sized 约束,因为这是最普遍最常见的情况。
如果我们希望一个泛型参数也可以支持 DST 类型,那么就应该为它专门加上 ?Sized 约束