泛型允许我们编写灵活且可重用的代码,适用于不同类型的数据,而无需为每种类型编写单独的实现。它帮助我们以类型安全且高效的方式编写能够处理任何类型值的代码。
借助泛型,我们可以为方法、函数、结构体、枚举和 Trait 定义占位符类型。
在 Rust 中使用泛型
我们可以通过查看 Rust HashMap 来理解泛型。
HashMap 使用泛型,可以创建可重用且高效的代码,通过单个实现就能适用于不同类型。
Rust HashMap 具有两种泛型类型,一种用于键,第二种用于值。
Rust HashMap 类型如下所示
HashMap<K, V>
其中 <K, V>
:K
是键的类型,V
是值的类型。
现在,当我们创建 HashMap 时,可以将任何类型赋给 K
和 V
。
let mut numbers: HashMap<i32, &str> = HashMap::new();
这里,尖括号 <i32, &str>
表示 HashMap 的键类型和值类型。键 K
的类型是 i32
,值 V
的类型是 &str
。
类似地,我们创建一个 HashMap 并将键和值都设置为 &str
类型。
let mut language_codes: HashMap<&str, &str> = HashMap::new();
使用泛型定义 HashMap 的类型,有助于我们处理 Rust 中众多任意类型。
要了解 HashMap 的基础知识,请访问 Rust HashMap。
注意
- 泛型或泛型类型使用单个字符,如
K
、V
、T
、U
,以区别于实际的具体类型,如String
、&str
、i32
。 - 按照惯例,
T
、U
用于任意类型K
、V
用于键值类型E
用于错误类型
示例:在 Rust 中使用泛型
use std::collections::HashMap;
fn main() {
// Create a HashMap with types i32 and &str
let mut numbers: HashMap<i32, &str> = HashMap::new();
// Insert values to numbers HashMap
numbers.insert(1, "One");
numbers.insert(2, "Two");
println!("Numbers: {:?}", numbers);
// Create a HashMap with types &str and &str
let mut language_codes: HashMap<&str, &str> = HashMap::new();
// Insert values to 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
。在结构体的内部,我们为 x
和 y
使用了 T
数据类型。
现在,要使用泛型结构体 Point
,我们可以初始化它并将其绑定到变量。
let int_point = Point { x: 1, y: 2 };
let float_point = Point { x: 1.1, y: 2.2 };
在这里,我们初始化了两次 Point
结构体,第一次使用整数值,第二次使用浮点数值。
示例:Rust 泛型结构体
fn main() {
// defining a struct with generic data type
#[derive(Debug)]
struct Point<T> {
x: T,
y: T,
}
// initializing a generic struct with i32 data type
let int_point = Point { x: 1, y: 2 };
// initializing a generic struct with f32 data type
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 泛型函数
我们还可以创建带有泛型类型作为参数的函数。
以下是泛型函数的语法。
// generic function with single generic type
fn my_function<T>(x: T, y: T) -> T {
// function body
// do something with `x` and `y`
}
// generic function with multiple generic types
fn my_function<T, U>(x: T, y: U) {
// function body
// do something with `x` and `y`
}
这里,函数定义中的 <T>
表示一个关于类型 T
的泛型函数。同样,<T, U>
表示一个关于类型 T
和 U
的泛型函数。
示例:Rust 泛型函数
fn main() {
// generic function to find minimum between two inputs
fn min<T: PartialOrd>(a: T, b: T) -> T {
if a < b {
return a;
} else {
return b;
}
}
// call generic function with integer type as parameters
let result1 = min(2, 7);
// call generic function with float type as parameters
let result2 = min(2.1, 1.1);
println!("Result1 = {}", result1);
println!("Result2 = {}", result2);
}
输出
Result1 = 2 Result2 = 1.1
在此示例中,我们创建了一个名为 min()
的函数,其泛型类型参数为 a: T
和 b: T
。类型参数 T
使用语法 <T: PartialOrd>
声明,这意味着 T
可以是实现了 PartialOrd
Trait 的任何类型。
PartialOrd
Trait 提供了比较类型值的方法,例如 <
和 >
。Rust 的这个特性称为 Trait 边界。如果我们不使用 <T: PartialOrder>
,Rust 将抛出编译错误:error[E0369]: binary operation `<` cannot be applied to type `T`
因此,我们应该将参数 T
限制为来自 std::cmp
模块的 PartialOrd
。
要了解更多关于 Trait 的信息,请访问 Rust Trait。