第十章 泛型
消除重复的代码
消除重复的步骤
- 识别重复的代码
- 提取重复的代码到函数体中, 并在函数签名中指定函数的输入和返回值
- 将重复的代码使用函数调用进行替换
泛型的功能
泛型: 提高代码的复用能力 -------处理重复代码的问题.
泛型是具体类型或其他属性的抽象代替:
- 使用泛型编写的代码不是最终的代码, 而是一种模板, 里面有一些“占位符”.
- 编译器在编译时将 “占位符” 替换为具体的类型.
fn largest<T>(list: &[T]) -> T {...}
如上例所示 类型的参数通常是一个大写字母, 通常使用T来代替. 首先 largest<T> 对泛型参数 T 进行了声明, 然后才在函数参数中进行使用该泛型参数 list: &[T].
泛型定义
函数定义中使用泛型
fn largest<T>(list: &[T]) -> T { // 使用泛型代替函数签名
let mut largest = list[0];
for &item in list {
if item > largest { // 这里会报错,这里只是表达我们可以这样实现, 为了消除错误,我们需要指定T实现std::cmp::PartialOrd的Trait, 后面修改
largest = item;
}
}
largest
}
fn main() {
let number_list = [32, 56, 23, 63, 220];
let result = largest(&number_list);
println!("The largest number is {}", result);
let char_list = vec!['y', 'm', 'a', 'q'];
let result = largest(&char_list);
println!("The larest char is {}", result);
}
在声明一个函数的时候,我们还可以不指定具体的参数或返回值的类型,而是由泛型参数来代替,(传进什么类型,传出什么类型).
fn id<T>(x:T) -> T { // 泛型函数
return x;
}
fn main() {
let int = id(0);
let string = id("Try");
println!("{}, {}", int, string);
}
Rust 会对泛型函数进行单态化处理.也就是在编译时,把所有用到的泛型函数的泛型参数展开,生成若干个函数.
结构体中的泛型
结构体中可以为每个成员都指定类型. 所以也可以精准的控制每个成员的泛型
struct Point<T> {
x: T,
y: T,
}
fn main() {
let integer = Point {x:5, y:7};
let string = Point {x:'a', y:'b'}; // 此时x,y 是同一种类型的
}
struct Point<T, U> {
x: T,
y: U,
}
fn main() {
let integer = Point {x:5, y:'c'}; // 此时x,y 可以是不同类型的
}
枚举中使用泛型
enum Option<T> {
Some(T),
None,
}
enum Result<T, E> {
Ok(T),
Err(E),
}
方法的定义中使用泛型
struct Point<T> {
x:T,
y:T,
}
impl<T> Point<T> { // 此方法所有类型都有
fn x(&self) -> &T {
&self.x
}
}
impl Point<i32> { // 只有在i32的类型上才有方法x1
fn x1(&self) -> &i32 {
&self.x
}
}
将T 放在impl关键字后, 表示在类型T上实现方法.指定具体类型后就是对具体类型实现的方法,其他类型不可以调用.
struct 中的泛型参数可以和方法的泛型类型参数不同
struct Point<T, U> {
x:T,
y:U,
}
impl<T, U> Point<T, U> {
// 此处的方法的泛型和struct中泛型类型就不同. 但是我认为这里主要是因为输入了一个新的不同类型的对象,并且要使用新对象里的泛型,所以才使用新的泛型.
fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {
Point {
x: self.x,
y: other.y,
}
}
}
fn main() {
let p1 = Point { x:5, y: 4};
let p2 = Point { x: "Hello", y: 'c' };
let p3 = p1.mixup(p2);
println!("p3.x = {}, p3.y = {}", p3.x, p3.y);
}
const 泛型(Rust 1.51 版本引入的重要特性)
针对类型实现的泛型, 所有的泛型都是为了抽象不同的类型, 那有没有针对值的泛型?
下面的代码中 [i32; 2], [i32; 3]是两个不同的类型:
fn display_array(arr: [i32; 3]) {
println!("{:?}", arr);
}
fn main() {
let arr: [i32; 3] = [1, 2, 3];
display_array(arr);
let arr: [i32;2] = [1,2]; // 类型不匹配
display_array(arr);
}
可以使用引用的方式进行修改.
fn display_array(arr: &[i32]) { // 可以是任意长度的数组
// fn display_array<T: std::fmt::Debug>(arr: &[T]) { // 使用泛型代替特定类型
println!("{:?}", arr);
}
fn main() {
let arr: [i32; 3] = [1, 2, 3];
display_array(&arr);
let arr: [i32;2] = [1,2];
display_array(&arr);
}
某些情况下不能使用引用, 这时需要使用 值的泛型.
fn display_array<T: std::fmt::Debug, const N: usize>(arr: [T; N]) { // N就是泛型参数
println!("{:?}", arr);
}
fn main() {
let arr: [i32; 3] = [1, 2, 3];
display_array(arr);
let arr: [i32; 2] = [1, 2];
display_array(arr);
}
const 泛型定义的语法是 const N: usize,表示 const 泛型 N ,它基于的值类型是 usize