|
|
|
|
# 泛型类型、特征和生存期
|
|
|
|
|
|
|
|
|
|
泛型,处理重复的工具。
|
|
|
|
|
|
|
|
|
|
## 通过提取函数来消除重复
|
|
|
|
|
|
|
|
|
|
泛型允许我们用表示多种类型的占位符替换特定类型,以消除代码重复。
|
|
|
|
|
|
|
|
|
|
![image-20230214100415253](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230214100415253.png)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 泛型
|
|
|
|
|
|
|
|
|
|
我们使用泛型来为函数签名或结构等项创建定义,然后可以将其用于许多不同的具体数据类型。
|
|
|
|
|
|
|
|
|
|
### 在函数定义中
|
|
|
|
|
|
|
|
|
|
在定义使用泛型的函数时,我们将泛型放在函数的签名中,通常在这里指定参数和返回值的数据类型。
|
|
|
|
|
|
|
|
|
|
不使用泛型时:
|
|
|
|
|
|
|
|
|
|
![image-20230214101609436](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230214101609436.png)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
泛型函数定义:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
fn largest<T>(list: &[T]) -> &T {}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
函数最大是对某种类型T的泛型。该函数有一个名为list的形参,它是类型T的值的切片。最大函数将返回对相同类型T的值的引用。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
![image-20230214103935848](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230214103935848.png)
|
|
|
|
|
|
|
|
|
|
`std::cmp::PartialOrd` 是 Rust 标准库中的一个 trait,它提供了一种比较类型实例的方法。该 trait 定义了关系运算符(例如小于号(`<`))的行为。
|
|
|
|
|
|
|
|
|
|
实现 `std::cmp::PartialOrd` trait 的类型可以使用这些关系运算符进行比较。这些比较可以用于实现排序算法,例如,您可以使用比较运算符对一组数据进行排序。[PartialOrd 文档。](https://doc.rust-lang.org/stable/std/cmp/trait.PartialOrd.html)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 在结构定义中
|
|
|
|
|
|
|
|
|
|
可以使用<>语法定义结构,在一个或多个字段中使用泛型类型参数。
|
|
|
|
|
|
|
|
|
|
![image-20230214111131732](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230214111131732.png)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
x和y都是泛型,但可以有不同的类型,可以使用多个泛型类型参数、
|
|
|
|
|
|
|
|
|
|
![image-20230214111655994](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230214111655994.png)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 在枚举定义中
|
|
|
|
|
|
|
|
|
|
同处理结构体一样,我们可以定义枚举来保存泛型数据类型的变体。例如Option<T>枚举。
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
enum Option<T> {
|
|
|
|
|
Some(T),
|
|
|
|
|
None,
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Result枚举是两种类型T和E的泛型,并且有两个变体,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 在方法定义中
|
|
|
|
|
|
|
|
|
|
![image-20230214115347188](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230214115347188.png)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在Point<T>上定义了一个名为x的方法,该方法返回对字段x中的数据的引用。
|
|
|
|
|
|
|
|
|
|
![](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230214143218912.png)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
该方法测量我们的点到坐标(0.0,0.0)处的点的距离,并使用仅适用于**浮点类型**的数学操作。类型不符时产生的问题:
|
|
|
|
|
|
|
|
|
|
![image-20230214150121126](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230214150121126.png)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
结构定义中的泛型类型参数并不总是与在同一结构的方法签名中使用的参数相同。具体如下:
|
|
|
|
|
|
|
|
|
|
![image-20230214153201354](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230214153201354.png)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 使用泛型的代码性能
|
|
|
|
|
|
|
|
|
|
使用泛型类型不会使程序比使用具体类型运行得更慢。Rust通过在编译时使用泛型执行代码的**单一化**来实现这一点。单一化是通过填充**编译时使用的具体类型**,将泛型代码转换为特定代码的过程。
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
#![allow(unused)]
|
|
|
|
|
fn main() {
|
|
|
|
|
let integer = Some(5);
|
|
|
|
|
let float = Some(5.0);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
当Rust编译这段代码时,它执行单化。在这个过程中,编译器读取Option<T>实例中使用的**值**,并识别出两种Option<T>:一种是i32,另一种是f64。因此,它将Option<T>的泛型定义扩展为两个专门用于i32和f64的定义,从而将泛型定义替换为特定的定义。
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
enum Option_i32 {
|
|
|
|
|
Some(i32),
|
|
|
|
|
None,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum Option_f64 {
|
|
|
|
|
Some(f64),
|
|
|
|
|
None,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
let integer = Option_i32::Some(5);
|
|
|
|
|
let float = Option_f64::Some(5.0);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
泛型Option<T>被替换为编译器创建的特定定义。因为Rust将泛型代码编译为每个实例中指定类型的代码,所以使用泛型没有运行时成本。当代码运行时,它的执行就像手工复制每个定义一样。单一化的过程使得Rust的泛型在运行时非常高效。
|