You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4.4 KiB

泛型类型、特征和生存期

泛型,处理重复的工具。

通过提取函数来消除重复

泛型允许我们用表示多种类型的占位符替换特定类型,以消除代码重复。

image-20230214100415253

泛型

我们使用泛型来为函数签名或结构等项创建定义,然后可以将其用于许多不同的具体数据类型。

在函数定义中

在定义使用泛型的函数时,我们将泛型放在函数的签名中,通常在这里指定参数和返回值的数据类型。

不使用泛型时:

image-20230214101609436

泛型函数定义:

fn largest<T>(list: &[T]) -> &T {}

函数最大是对某种类型T的泛型。该函数有一个名为list的形参,它是类型T的值的切片。最大函数将返回对相同类型T的值的引用。

image-20230214103935848

std::cmp::PartialOrd 是 Rust 标准库中的一个 trait,它提供了一种比较类型实例的方法。该 trait 定义了关系运算符(例如小于号(<))的行为。

实现 std::cmp::PartialOrd trait 的类型可以使用这些关系运算符进行比较。这些比较可以用于实现排序算法,例如,您可以使用比较运算符对一组数据进行排序。PartialOrd 文档。

在结构定义中

可以使用<>语法定义结构,在一个或多个字段中使用泛型类型参数。

image-20230214111131732

x和y都是泛型,但可以有不同的类型,可以使用多个泛型类型参数、

image-20230214111655994

在枚举定义中

同处理结构体一样,我们可以定义枚举来保存泛型数据类型的变体。例如Option枚举。

enum Option<T> {
    Some(T),
    None,
}

Result枚举是两种类型T和E的泛型,并且有两个变体,

在方法定义中

image-20230214115347188

在Point上定义了一个名为x的方法,该方法返回对字段x中的数据的引用。

该方法测量我们的点到坐标(0.0,0.0)处的点的距离,并使用仅适用于浮点类型的数学操作。类型不符时产生的问题:

image-20230214150121126

结构定义中的泛型类型参数并不总是与在同一结构的方法签名中使用的参数相同。具体如下:

image-20230214153201354

使用泛型的代码性能

使用泛型类型不会使程序比使用具体类型运行得更慢。Rust通过在编译时使用泛型执行代码的单一化来实现这一点。单一化是通过填充编译时使用的具体类型,将泛型代码转换为特定代码的过程。

#![allow(unused)]
fn main() {
	let integer = Some(5);
	let float = Some(5.0);
}

当Rust编译这段代码时,它执行单化。在这个过程中,编译器读取Option实例中使用的,并识别出两种Option:一种是i32,另一种是f64。因此,它将Option的泛型定义扩展为两个专门用于i32和f64的定义,从而将泛型定义替换为特定的定义。

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被替换为编译器创建的特定定义。因为Rust将泛型代码编译为每个实例中指定类型的代码,所以使用泛型没有运行时成本。当代码运行时,它的执行就像手工复制每个定义一样。单一化的过程使得Rust的泛型在运行时非常高效。