类型系统与多态性
- Rust一切皆表达式,表达式皆有值,值皆有类型,Rust中一切皆类型
- 现代编程语言包含三种多态形式:参数化多态、Ad-hoc多态和子类型多态:参数化多态和Ad-hoc是静多态,子类型多态是动多态
- 参数化多态指泛型,Ad-hoc多态叫特定多态:Haskell中是Typeclass,Rust中是trait;子类型多态出自面向对象语言
- Rust没有GC,内存由编译器分配,Rust代码被编译为LLVM IR,其中携带内存分配信息
- Rust也有少量的动态大小类型(DST),比如str,因为编译器不可能实现直到字符串,因此字符串切片&str是引用类型,它携带指针和长度信息
- Rust还支持零大小类型(ZST),比如单元类型和单元结构体,大小是0
- 如果ZST类型是空,那么底类型表示无,它是!,被称为Bang Type。
- ::<>是turbofish操作符。is_positive()可以判断正负
- Rust的泛型是静多态,编译器不管是泛型枚举、泛型函数还是泛型结构体,都会被单态化(Monomorphization)(静态分发)
- trait有4种用法:接口抽象、泛型约束、抽象类型和标签trait
- 孤儿原则(Orphan Rule):如果要实现某个trait,该trait和要实现该trait的类型至少有一个在当前crate中定义。
- Rust的trait限定与Java的泛型限定、Ruby和Python的Duck Typeing、Golang的Structural Typeing类似。trait是类型,是集合impl<T: A + B> C for T意思是为所有T属于A交B实现Trait C
- 泛型中使用trait限定,可以将类型的范围根据类型行为限定精确可控的范围。而OOP那套,可以使用trait object,它将在运行期根据虚表指针从虚表(析构函数、大小、对齐和方法等信息)找出正确指针,然后动态调用,这就是动态分发,区别于泛型静态分发
- 只有当trait的Self类型参数不能被限定为Sized且trait中所有方法都是对象安全时才能作为trait对象使用
- Sized、Unsize和?Sized的关系是,?Sized包含前者,Sized在编译期确定大小,而UnSize是不确定的
- 对象安全的方法必须满足三点之一
- 方法受Self: Sized约束
- 方法签名同时满足三点
- 不包含任何泛型参数。(否则trait对象在Vtable中将不确定调用哪个方法)
- 第一参数必须为Self类型或可以解引用为Self的类型。(如self、&self、&mut self和self: Box
- Self不能出现在除第一参数外的地方。
- trait中不包含关联常量,不过可以增加默认的关联常量,只需要使用const关键字
- Rust提供了5个重要标签trait,定义在std::marker,分别是Sized trait、Unsize trait、Copy trait、Send trait和Sync trait
- 动态大小类型不能随意使用,需遵循三条限制规则:
- 只允许通过fat pointer来操作Unsize,类型,如&[T]或&Trait
- 变量、参数和枚举变量不能使用DST
- 结构体最后一个字段可以使用DST,其他字段不行
- Copy trait继承自Clone trait,因此实现Copy功能同时需要实现Clone trait。Copy行为是隐式行为,开发者不能重载,它是简单的位复制,发生执行在变量绑定、函数参数传递和函数返回等场景中
- 任何类型都能实现Clone trait,但不是所有类型都能实现Copy trait,前提是所有成员都实现了Copy trait
- Rust可以通过实现Deref trait来自定义解引用操作,如果类型T实现了Deref<Target=U>,则该类型T引用或指针在引用时自动转换为U
- Rust的解引用有std::ops::Deref的.deref()、.as_ref()、std:borrow::Borrow的.borrow()、&*x和&x[..]
- From和Into是定义于std::convert模块中的两个trait,定义了from和into两个方法互为&str和String类型的反操作。标准库中还包含TryFrom和TryInto两种trait,它们是错误处理版本
- Rust标准库中包含了AsRef和AsMut两种trait,将值分别转换为不可变引用和可变引用
- Box
( pub struct Box<T: ?Sized>(Unique<T>);
)和Fn、FnMut、FnOnce、Sized等都加上#[fundamental]属性,代表享有特权,不必遵守孤儿规则 - 除了Rust,Rust还有重叠规则(Overlap),规则规定不能为重叠的类型实现同一个trait
- 迭代元素时,只能按值迭代,有时必须重新分配数据,不能通过引用来复用原始数据,为了支持引用类型,可以重用内部缓存区不需要重新分配内存,需要更高级的类型多态性,即泛型关联类型(Generic Associated Type, GAT)