newtype

何为 newtype?简单来说,就是使用元组结构体的方式将已有的类型包裹起来:struct Meters(u32);,那么此处 Meters 就是一个 newtype

!永不返回类型

! 用来说明一个函数永不返回任何值 panic 的返回值是 !

Sized 和不定长类型 DST(dynamically sized types)

从编译器何时能获知类型大小的角度出发,可以分成两类:

  • 定长类型( sized ),这些类型的大小在编译时是已知的
  • 不定长类型( unsized ),与定长类型相反,它的大小只有到了程序运行时才能动态获知,这种类型又被称之为 DST

动态大小类型 DST

集合虽然底层数据可动态变化,感觉像是动态大小的类型。但是实际上,这些底层数据只是保存在堆上,在栈中还存有一个引用类型,该引用包含了集合的内存地址、元素数目、分配空间信息,通过这些信息,编译器对于该集合的实际大小了若指掌,最最重要的是:栈上的引用类型是固定大小的,因此它们依然是固定大小的类型。

正因为编译器无法在编译期获知类型大小,若你试图在代码中直接使用 DST 类型,将无法通过编译。

Rust 中常见的 DST 类型有: s[T]dyn Trait,它们都无法单独被使用,必须要通过引用或者 Box 来间接使用 。

Sized 特征

使用泛型时,Rust 如何保证我们的泛型参数是固定大小的类型呢?

#![allow(unused)]
fn main() {
fn generic<T>(t: T) {
    // --snip--
}
}

奥秘在于编译器自动帮我们加上了 Sized 特征约束:

#![allow(unused)]
fn main() {
fn generic<T: Sized>(t: T) {
    // --snip--
}
}

所有在编译时就能知道其大小的类型,都会自动实现 Sized 特征.

假如想在泛型函数中使用动态数据类型怎么办?可以使用 ?Sized 特征

#![allow(unused)]
fn main() {
fn generic<T: ?Sized>(t: &T) {
    // --snip--
}
}

?Sized 特征用于表明类型 T 既有可能是固定大小的类型,也可能是动态大小的类型。还有一点要注意的是,函数参数类型从 T 变成了 &T,因为 T 可能是动态大小的,因此需要用一个固定大小的指针(引用)来包裹它。

每一个特征都是一个可以通过名称来引用的动态大小类型。因此如果想把特征作为具体的类型来传递给函数,你必须将其转换成一个特征对象:诸如 &dyn Trait 或者 Box<dyn Trait> (还有 Rc<dyn Trait>)这些引用类型。