跳到主要内容

Rust泛型

提示
  1. 泛型的概念:Rust 中的泛型允许编写适用于多种数据类型的灵活且可重用代码,避免为每种类型单独编写实现。
  2. 泛型在 Rust 中的应用:泛型用于定义方法、函数、结构体、枚举和特性,例如在 HashMap<K, V> 中,KV 是泛型类型。
  3. 泛型结构体和函数:可以创建带有泛型参数的结构体和函数,使得代码更加通用和灵活,例如 struct Point<T> { x: T, y: T, }fn my_function<T>(x: T, y: T) -> T { ... }

泛型允许我们编写灵活且可重用的代码,适用于不同类型的数据,而无需为每种类型编写单独的实现。它帮助我们以类型安全且高效的方式编写可以处理任何类型值的代码。

利用泛型,我们可以为方法、函数、结构体、枚举和特性定义占位符类型。

在 Rust 中使用泛型

我们可以通过查看 Rust HashMap 来理解泛型。

HashMap 使用泛型,允许创建可重用且高效的代码,因为它是一个适用于不同类型的单一实现。

Rust 的 HashMap 有两种泛型类型,一个用于键,另一个用于值。

HashMap 类型看起来像这样:

HashMap<K, V>

其中 <K, V>K 是键的类型,V 是值的类型。

现在,当我们创建一个 HashMap 时,可以将任何类型设置为 KV

let mut numbers: HashMap<i32, &str> = HashMap::new();

这里,尖括号 <i32, &str> 表示 HashMap 的键类型和值类型。键的类型 Ki32,值的类型 V&str

类似地,我们创建一个 HashMap 并将键和值的类型都设置为 &str

let mut language_codes: HashMap<&str, &str> = HashMap::new();

使用泛型来定义 HashMap 的类型,帮助我们处理 Rust 中可用的众多任意类型。

要了解 HashMap 的基础知识,请访问 Rust HashMap

注意:

  • 泛型或泛型类型使用单个字符如 KVTU 来区分实际的具体类型,如 String&stri32
  • 作为惯例,
    • TU 用于任意类型
    • KV 用于键值类型
    • E 用于错误类型

示例:在 Rust 中使用泛型

use std::collections::HashMap;

fn main() {
// 创建一个类型为 i32 和 &str 的 HashMap
let mut numbers: HashMap<i32, &str> = HashMap::new();

// 向 numbers HashMap 插入值
numbers.insert(1, "One");
numbers.insert(2, "Two");

println!("Numbers: {:?}", numbers);

// 创建一个类型为 &str 和 &str 的 HashMap
let mut language_codes: HashMap<&str, &str> = HashMap::new();

// 向 language_codes HashMap 插入值
language_codes.insert("EN", "English");
language_codes.insert("NE", "Nepali");

println!("Language Codes: {:?}", language_codes);
}

输出

Numbers: {1: "One", 2: "Two"}
Language Codes: {"EN": "English", "NE": "Nepali"}

在这里,我们创建了两个 HashMap 数据结构:HashMap<i32, &str>HashMap<&str, &str>

这是可能的,因为 HashMap 实现使用了泛型,可以适用于不同类型。

Rust 中的泛型结构体

我们可以使用泛型在 Rust 中创建泛型结构体数据结构。例如,我们可以声明一个带有泛型参数的结构体。

struct Point<T> {
x: T,
y: T,
}

这里,我们创建了一个带有泛型类型参数 `T` 的结构体 `Point`。在结构体的体内,我们使用了 `T` 数据类型作为 `x` 和 `y`。

现在,要使用泛型结构体 `Point`,我们可以初始化它并将其绑定到一个变量。
```rust
let int_point = Point { x: 1, y: 2 };
let float_point = Point { x: 1.1, y: 2.2 };

这里,我们初始化了两次 Point 结构体,第一次使用整数值,第二次使用浮点数值。

示例:Rust 中的泛型结构体

fn main() {
// 使用泛型数据类型定义结构体
#[derive(Debug)]
struct Point<T> {
x: T,
y: T,
}

// 使用 i32 数据类型初始化泛型结构体
let int_point = Point { x: 1, y: 2 };

// 使用 f32 数据类型初始化泛型结构体
let float_point = Point { x: 1.1, y: 2.2 };

println!("int_point: {:?}", int_point);
println!("float_point: {:?}", float_point);
}

输出

int_point: Point { x: 1, y: 2 }
float_point: Point { x: 1.1, y: 2.2 }

Rust 中的泛型函数

我们也可以创建带有泛型类型参数的函数。

这是泛型函数的语法。

// 带有单个泛型类型的泛型函数
fn my_function<T>(x: T, y: T) -> T {
// 函数体
// 对 `x` 和 `y` 进行一些操作
}

// 带有多个泛型类型的泛型函数
fn my_function<T, U>(x: T, y: U) {
// 函数体
// 对 `x` 和 `y` 进行一些操作
}

这里,函数定义中的 <T> 表示对类型 T 的泛型函数。同样地,<T, U> 表示对类型 TU 的泛型函数。

示例:Rust 中的泛型函数

fn main() {
// 泛型函数用于查找两个输入中的最小值
fn min<T: PartialOrd>(a: T, b: T) -> T {
if a < b {
return a;
} else {
return b;
}
}

// 使用整数类型作为参数调用泛型函数
let result1 = min(2, 7);

// 使用浮点类型作为参数调用泛型函数
let result2 = min(2.1, 1.1);

println!("Result1 = {}", result1);
println!("Result2 = {}", result2);
}

输出

Result1 = 2
Result2 = 1.1

在这个示例中,我们创建了一个带有泛型类型参数 a: Tb: T 的函数 min()。类型参数 T 使用 <T: PartialOrd> 语法声明,这意味着 T 可以是任何实现了 PartialOrd 特质的类型。

PartialOrd 特质提供了一种比较类型值的方法,例如 <>。这是 Rust 的特性之一,称为特质界限。如果我们不使用 <T: PartialOrd>,Rust 将抛出编译错误:error[E0369]: 不能对类型 T 使用二元操作符 < .

因此,我们应该将参数 T 限制为来自 std::cmp 模块的 PartialOrd

要了解更多关于特质的信息,请访问 Rust 特质