Appearance
21.1 数据结构中的泛型
有时候,我们需要针对多种类型进行统一的抽象,这就是泛型。泛型可以将“类型”作为参数,在函数或者数据结构中使用。
再以我们熟悉的 Option 类型举例。它就是一个泛型 enum 类型,其参数声明在尖括号<>中。
rust
enum Option<T> {
Some(T),
None,
}
这里的<T>
实际上是声明了一个“类型”参数。在这个 Option 内部,Some(T)
是一个 tuple struct,包含一个元素类型为 T。这个泛型参数类型 T,可以在使用时指定具体类型。
rust
let x: Option<i32> = Some(42);
let y: Option<f64> = None;
在上述第一行代码中,泛型参数 T 被具体化成了 i32,x 的类型,在这里是Option<i32>
;在第二行代码中,泛型参数 T 被具体化成了 f64,y 的类型,在这里是Option<f64>
。
泛型参数可以有多个也可以有默认值。比如:
rust
struct S<T=i32> {
data: T
}
fn main() {
let v1 = S { data: 0};
let v2 = S::<bool> { data: false};
println!("{} {}", v1.data, v2.data);
}
对于上例中的泛型参数 T,我们可以在使用的时候不指定类型参数。如果不指定的话,参数默认为 i32,也可以在使用的时候指定为其他类型。
使用不同类型参数将泛型类型具体化后,获得的是完全不同的具体类型。如Option<i32>
和Option<i64>
是完全不同的类型,不可通用,也不可相互转换。当编译器生成代码的时候,它会为每一个不同的泛型参数生成不同的代码。
各种自定义复合类型都可以携带任意的泛型参数。Rust 规定,所有的泛型参数必须是真的被使用过的。下面的代码就会报错:
rust
struct Num<T> {
data: i32
}
这个结构体声明了一个泛型参数,但是却并没有使用它。编译器会对这个问题报错,说有泛型参数从来没有使用过。按下面这样写就没有问题了:
rust
struct Num<T> {
data: Option<T>
}