无论是前面提到的Option<T>还是Result<T,E>,甚至集合类型Vec<T>等都有泛型参数。
通过泛型能够将不同类型的相同行为用一个函数实现,避免了重复代码。
泛型函数
对于两个只在名称和签名类型上不同的函数,通过使用泛型可以消除重复代码。
Rust的类型的命令规范使用驼峰命名法。
一个找到切片中最大元素的函数,可以写为:
fn largest<T>(list: &[T]) -> T {
let mut largest = list[0];
for &item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}上面的代码无法编译通过,因为代码内又>比较操作,并不是所有类型都能够进行这个操作的。需要类型实现std::cmp::PartialOrd trait才可以。
泛型结构体
struct Point<T> {
x: T,
y: T,
}定义了一个可以存储任何T类型的数据。因为Rust是强类型语言,所以上面的x和y的类型必须相同。如果需要不同,那么可以使用两个泛型参数:
struct Point<T,U> {
x: T,
y: U,
}泛型枚举
最经典的例子就是前面所说的Option<T>
enum Option<T> {
Some(T),
None,
}枚举也可以又多个泛型参数,如Result<T,E>
enum Result<T,E> {
Ok(T),
Err(E),
}泛型方法
为结构体或者枚举实现的方法也可以使用泛型参数
enum Point<T> {
x: T,
y: T,
}
impl <T> for Point<T> {
fn x(&self) -> &T {
&self.x
}
}还可以为特定的类型实现特定的方法,例如
impl Point<f32> {
fn distance_from_origin(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}结构体中的泛型参数与其方法的泛型参数不要求一致。
struct Point<T, U> {
x: T,
y: U,
}
impl<T, U> Point<T, U> {
fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {
Point {
x: self.x,
y: other.y,
}
}
}如上,mixup的结果的Point的两个参数的类型可以来自两个不同的Point的不同类型
fn main() {
let p1 = Point { x: 5, y: 10.4 };
let p2 = Point { x: "Hello", y: 'c'};
let p3 = p1.mixup(p2);
println!("p3.x = {}, p3.y = {}", p3.x, p3.y);
}泛型的性能问题
泛型不会有任何性能问题,Rust会在编译期执行泛型代码的单态化,也就是根据将实际的类型填入泛型参数得到具体有类型代码。相当于Rust为使用的类型生成了对应的条目,与使用具体的类型一样当然没有性能问题。
tags: 泛型