newtype模式
除了高级trait中用到的newtype模式外,newtype还可以用于抽象一些类型的实现细节,例如封装类型暴露出与内置内容不同的共有API,限制其功能。
隐藏内部的泛型类型。比如提供一个封装了HashMap<i32, String>的People类型。这样用户只是用People的公共API,不知道底层类型。
类型别名
通过type关键字可以获得给与现有类型另一个别名的。别名不是新的类型,而是完全被当作被起别名的类型处理。与c++中的type和using作用类型。
类型别名的主要用途是减少重复。当类型很长的时候非常有用。并且更加具有意义。
就像std::io::Error中函数但部分会返回Result<..., std::io::Error>错误一样,所以也取了一个别名
type Result<T> = std::result::Result<T, std::io::Error>;这样使用的时候只用Result<T>就足够了。
从不返回的never type
Rus中一个叫做!的特殊类型。它没有值,称为newver type。在函数从不返回的时候充当返回值。例如:
fn bar() -> ! {
// --snip--
panic!();
}描述 ! 的行为的正式方式是 never type 可以强转为任何其他类型。在match表达式中,要求match的分支必须返回相同的类型,但是存在下面的情况:
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
impl<T> Option<T> {
pub fn unwrap(self) -> T {
match self {
Some(val) => val,
None => panic!("called `Option::unwrap()` on a `None` value"),
}
}
}即continue和panic!,Rust在计算类型的时候会将它们当作!类型,所以可以编译通过,但是实际上,它们并不产生值,而是控制程序的流程,比如continue将控制权移交给上层循环,panic!终止程序。
动态大小类型与Sized trait
Rust 需要知道应该为特定类型的值分配多少内存,同时所有同一类型的值必须使用相同数量的内存。但是Rust中是有动态大小类型的,被称为DST或者unsized types。只有在运行的时候才知道大小的类型。
以str这个动态大小类型进行说明。Rust中是无法创建str,对于这种类型的处理器,Rust是创建了其引用&str的,因为&str的大小是确定的。
Rust 中动态大小类型的常规用法:他们有一些额外的元信息来储存动态信息的大小。这引出了动态大小类型的黄金规则:必须将动态大小类型的值置于某种指针之后。
比如 Box<str> 或 Rc<str>。
为了处理 DST,Rust 有一个特定的 trait 来决定一个类型的大小是否在编译时可知:这就是 Sized trait。能够在编译期就确定大小的类型都实现了这个trait。
Rust 隐式的为每一个泛型函数增加了 Sized bound。也就是说,对于如下泛型函数定义:
fn generic<T>(t: T) {
// --snip--
}
// 等价于
fn generic<T: Sized>(t: T) {
// --snip--
}泛型函数默认只能用于在编译时已知大小的类型。然而可以使用如下特殊语法来放宽这个限制:
fn generic<T: ?Sized>(t: &T) {
// --snip--
}?Sized这个写法只能用于Sized这个trait,会覆盖默认泛型参数拥有固定大小的默认规则。因为T类型可能不是固定大小的,所以需要置于某种指针之后,可以看到函数的参数由T变为了&T。