在 Rust 编程中使用泛型

本文的内容将涉及泛型定义函数、结构体、枚举和方法, 还将讨论泛型如何影响代码性能 。1.摘要Rust中的泛型可以让我们为像函数签名或结构体这样的项创建定义, 这样它们就可以用于多种不同的具体数据类型 。下面的内容将涉及泛型定义函数、结构体、枚举和方法, 还将讨论泛型如何影响代码性能 。

在 Rust 编程中使用泛型

文章插图
2.在函数定义中使用泛型当使用泛型定义函数时,本来在函数签名中指定参数和返回值的类型的地方,会改用泛型来表示 。采用这种技术,使得代码适应性更强,从而为函数的调用者提供更多的功能 , 同时也避免了代码的重复 。
看下面的代码例子, 定义了两个函数, 功能都差不多,作用是分别寻找slice中最大的i32和slice中最大的char, 只是数据类型不同 。
fn largest_i32(list: &[i32]) -> &i32 {let mut largest = &list[0];for item in list {if item > largest {largest = item;}}largest}fn largest_char(list: &[char]) -> &char {let mut largest = &list[0];for item in list {if item > largest {largest = item;}}largest}fn mAIn() {let number_list = vec![34, 50, 25, 100, 65];let result = largest_i32(&number_list);println!("The largest number is {}", result);let char_list = vec!['y', 'm', 'a', 'q'];let result = largest_char(&char_list);println!("The largest char is {}", result);}编译一下代码, 输出如下:
在 Rust 编程中使用泛型

文章插图
我们现在需要定义一个新函数, 引进泛型参数来消除这种因数据类型不同而导致的函数重复定义 。为了参数化这个新函数中的这些类型,我们需要为类型参数命名,道理和给函数的形参起名一样 。任何标识符都可以作为类型参数的名字 。这里选用 T,因为传统上来说,Rust 的类型参数名字都比较短 , 通常仅为一个字母,同时,Rust 类型名的命名规范是首字母大写驼峰式命名法(UpperCamelCase) 。T 作为 “type” 的缩写是大部分 Rust 程序员的首选 。
如果要在函数体中使用参数,就必须在函数签名中声明它的名字,好让编译器知道这个名字指代的是什么 。同理,当在函数签名中使用一个类型参数时,必须在使用它之前就声明它 。为了定义泛型版本的 largest 函数,类型参数声明位于函数名称与参数列表中间的尖括号 <> 中,像这样:
fn largest<T>(list: &[T]) -> &T可以这样理解这个定义:函数 largest 有泛型类型 T 。它有个参数 list,其类型是元素为 T 的 slice 。largest 函数会返回一个与 T 相同类型的引用 。
按照这个思想, 我们将代码改造如下:
fn largest<T>(list: &[T]) -> &T {let mut largest = &list[0];for item in list {if item > largest {largest = item;}}largest}fn main() {let number_list = vec![34, 50, 25, 100, 65];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 largest char is {}", result);}一切似乎很顺利, 尝试编译这段代码, 编译器结果如下:
在 Rust 编程中使用泛型

文章插图
这次编译没有通过的原因Rust编译器用绿色标识出来了, 缺少一个: std:cmp::PartialOrd, 先暂且认为这个是Rust标准库要求的东西, 加上重新编译一下试试:
fn largest<T: std::cmp::PartialOrd>(list: &[T]) -> &T {let mut largest = &list[0];for item in list {if item > largest {largest = item;}}largest}重新编译结果如下:
在 Rust 编程中使用泛型

文章插图
我们在代码中下了一个断点, 能够执行到此处说明代码已经没有问题 。实际上上面这个错误表明 largest 的函数体不能适用于 T 的所有可能的类型 。因为在函数体需要比较 T 类型的值,不过它只能用于我们知道如何排序的类型 。为了开启比较功能,标准库中定义的 std::cmp::PartialOrd trait 可以实现类型的比较功能, 我们限制 T 只对实现了 PartialOrd 的类型有效后代码就可以编译了,因为标准库为 i32 和 char 实现了 PartialOrd 。
3.在结构体中使用泛型同样也可以用 <> 语法来定义结构体,它包含一个或多个泛型参数类型字段 。下面的代码片段定义了一个可以存放任何类型的 x 和 y 坐标值的结构体 Point:


推荐阅读