Rust进阶-part2-泛型
Rust进阶[part2]_泛型
泛型概述
在定义函数时运用泛型,可将原本函数签名里明确指定参数和返回值类型的部分,用泛型来替代。这种方式能增强代码的适应性,为函数调用者赋予更多功能,还能避免代码重复。
fn add<T>(a:T, b:T) -> T{a + b
}
不过,并非所有的T类型都能进行相加操作,此时会提示错误:
genertic_type.rs(5, 9): consider restricting type parameter 'T' with trait 'Add': ': std::ops::Add<Output = T>'
修正后的代码如下:
fn add<T: std::ops::Add<Output = T>>(a: T, b: T) -> T {a + b
}
使用场景
在函数定义中使用泛型
fn largest<T: std::cmp::PartialOrd>(list: &[T]) -> &T {let mut largest = &list[0];for item in list {if item > largest {largest = item;}}largest
}
在结构体中使用泛型
struct Point<T> {x: T,y: T,
}// 实例化泛型结构体
let integer = Point { x: 5, y: 10 };
let float = Point { x: 1.0, y: 4.0 };
在枚举里面使用泛型
enum Result<T, E> {Ok(T),Err(E),
}// 实例化泛型枚举
fn divide(numerator: f64, denominator: f64) -> Result<f64, String> {if denominator == 0.0 {Err("Division by zero".to_string())} else {Ok(numerator / denominator)}
}
impl之后声明泛型T
泛型参数可以和结构体定义中声明的泛型参数不一样。
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,}}
}// 示例用法
let p1 = Point { x: 5, y: 10.4 };
let p2 = Point { x: "Hello", y: 'c' };
let p3 = p1.mixup(p2);
const泛型
// 定义一个固定大小的数组类型
struct ArrayBuffer<T, const N: usize> {data: [T; N],len: usize,
}impl<T, const N: usize> ArrayBuffer<T, N>
whereT: Default + Copy,
{fn new() -> Self {ArrayBuffer {data: [Default::default(); N],len: 0,}}
}// 创建一个可以存储10个i32的缓冲区
let buffer: ArrayBuffer<i32, 10> = ArrayBuffer::new();
where子句可以直接写在泛型参数后面,例如:
// 写法1:使用where子句
fn new_array_buffer<T, const N: usize>() -> ArrayBuffer<T, N>
whereT: Default + Copy,
{ ... }// 写法2:直接在泛型参数后指定约束
fn new_array_buffer<T: Default + Copy, const N: usize>() -> ArrayBuffer<T, N> { ... }
泛型代码的性能
Rust通过在编译时对泛型代码进行单态化来保证效率。
当代码运行时,其执行效率和手写每个具体定义的重复代码一样。正是这个单态化过程,使得Rust泛型在运行时极为高效。
// 泛型代码
fn add<T: std::ops::Add<Output = T>>(a: T, b: T) -> T {a + b
}// 单态化后的代码示例
fn add_i32(a: i32, b: i32) -> i32 {a + b
}fn add_f64(a: f64, b: f64) -> f64 {a + b
}