Sized trait
1 - Sized trait的std文档
https://doc.rust-lang.org/std/marker/trait.Sized.html
pub trait Sized { }
在编译时已知常量大小的类型。
所有类型参数的隐含边界均为 Sized
。如果不合适,可以使用特殊语法 ?Sized
删除此绑定。
struct Foo<T>(T);
struct Bar<T: ?Sized>(T);
// struct FooUse(Foo<[i32]>); // 错误:没有为 [i32] 实现大小调整
struct BarUse(Bar<[i32]>); // OK
一个例外是 trait 的隐式 Self
类型。 trait 没有隐式 Sized
绑定,因为它与 trait 对象 不兼容,根据定义,trait 需要与所有可能的实现者一起使用,因此可以为任意大小。
尽管 Rust 允许您将 Sized
绑定到 trait,但是以后您将无法使用它来形成 trait 对象:
trait Foo { }
trait Bar: Sized { }
struct Impl;
impl Foo for Impl { }
impl Bar for Impl { }
let x: &dyn Foo = &Impl; // OK
// let y: &dyn Bar = &Impl; // 错误:无法将 trait `Bar` 创建成对象
备注:trait object的要求之一就是trait不能是Sized,这也可以作为禁止将某个trait用作trait object的方式
2 - Sized trait的源码
https://github.com/rust-lang/rust/blob/master/library/core/src/marker.rs
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "sized"]
#[rustc_on_unimplemented(
message = "the size for values of type `{Self}` cannot be known at compilation time",
label = "doesn't have a size known at compile-time"
)]
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
#[rustc_specialization_trait]
pub trait Sized {
// Empty.
}
3 - [Rust编程之道笔记]Sided trait
Sized trait 非常重要,编译期用它来识别在编译期确定大小的类型。
#[lang = "sized"]
pub trait Sized {
// Empty.
}
Sized trait 是空 trait,仅仅作为标签 trait 供编译期使用。真正起"打标签"作用的是属性 #[lang = "sized"]
。该属性lang表示Sized trait供rust语言本身使用,声明为 “sized”,称为语言项(Lang Item)。
rust语言中大部分类型都是默认 Sized ,如果需要使用动态大小类型,则需要改为 <T: ?Sized>
限定。
struct Foo<T>(T);
struct Bar<T: ?Sized>(T);
Sized, Unsize和 ?Sized的关系
-
Sized 标记的是在编译期可确定大小的类型
-
Unsized 标记的是动态大小类型,在编译期无法确定其大小
目前rust中的动态类型有 trait 和 [T]
其中 [T] 代表一定数量的T在内存中的一次排列,但不知道具体的数量,所以大小是未知的。
-
?Sized 标记的类型包含了 Sized 和 Unsized 所标识的两种类型。
所以泛型结构体
struct Bar<T: ?Sized>(T);
支持编译期可确定大小类型和动态大小类型两种类型。
动态大小类型的限制规则
- 只可以通过胖指针来操作 Unsize 类型,如
&[T]
或者&trait
- 变量,参数和枚举变量不能使用动态大小类型
- 结构体中只有最有一个字段可以使用动态大小类型,其他字段不可以使用