提取函数消除重复
fn main() {let number_list = vec![34, 50, 25, 100, 65];let mut largest = number_list[0];for number in number_list {if number > largest {largest = number;}}println!("The largest number is {}", largest);}
新增需求,增对第二个 vector 也挑出最大值
fn main() {let number_list = vec![34, 50, 25, 100, 65];let mut largest = number_list[0];for number in number_list {if number > largest {largest = number;}}println!("The largest number is {}", largest);let number_list = vec![102, 34, 6000, 89, 54, 2, 43, 8];let mut largest = number_list[0];for number in number_list {if number > largest {largest = number;}}println!("The largest number is {}", largest);}
重复代码
- 重复代码的危害
- 容易出错
- 需求变更时需要在多出进行修改
- 消除重复:提取函数
```rust
fn largest(list: &[i32]) -> i32 {
let mut largest = list[0];
for &item in list {
} largest }if item > largest {largest = item;}
fn main() { let number_list = vec![34, 50, 25, 100, 65]; let result = largest(&number_list); println!(“The largest number is {}”, result);
let number_list = vec![102, 34, 6000, 89, 54, 2, 43, 8];let result = largest(&number_list);println!("The largest number is {}", result);
}
<a name="FmkmE"></a>### 消除重复的步骤- 识别重复代码- 提取重复代码到函数体中,并在函数签名中指定函数的输入和返回值- 将重复的代码使用函数调用进行替代<a name="m7XOX"></a>### 泛型- 泛型:提高代码**复用**能力- 处理重复代码的问题- 泛型是具体类型或其他属性的抽象代替- 编写的代码不是最终的代码,而是一种**模板**,里面有一些**占位符**- 编译器在**编译时**将“占位符”**替换为具体的类型**- 例如:`fn largest<`**`T`**`>(list: &[`**`T`**`]) -> `**`T`**` {...}`> 这个函数的定义使用了**泛型类型参数**,这个函数的定义其实就是一个模板,里面有一些占位符,> 这个大写的 T,就是占位符,写代码的时候 T ,它可以是任意的类型,但是在编译的过程中,> 编译器会根据你具体的使用,把 T 替换成具体的类型,这个过程叫做 **单态化**。- 类型参数:- 很短,通常一个字母- CamelCase- T:type 的缩写<a name="RPmcQ"></a>### 函数定义中的泛型- 泛型函数:- 参数类型- 返回类型替换成字符类型的切片```rustfn 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);}fn largest(list: &[i32]) -> i32 {let mut largest = list[0];for &item in list {if item > largest {largest = item;}}largest}
把 largest 使用泛型来进行定义 fn largest<T>(list: &[T]) -> T {}
函数 largest 它有泛型的类型参数 T,它接受一个名为 list 的参数,类型为切片,切片里的元素类型是 T。 而这个函数的返回值类型也是 T。
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);}fn largest<T>(list: &[T]) -> T {let mut largest = list[0];for &item in list {if item > largest {largest = item;}}largest}
运行出错
error[E0369]: binary operation `>` cannot be applied to type `T`--> src/main.rs:14:17|14 | if item > largest {| ---- ^ ------- T| || T|help: consider restricting type parameter `T`|11 | fn largest<T: std::cmp::PartialOrd>(list: &[T]) -> T {| ^^^^^^^^^^^^^^^^^^^^^^error: aborting due to previous errorFor more information about this error, try `rustc --explain E0369`.error: could not compile `fanxing`To learn more, run the command again with --verbose.
比较大小的运算符,不能应用于类型 T,consider restricting type parameter
T考虑限制这个类型参数 T。 让它实现 >std::cmp::PartialOrd这个 trait,用来实现比较功能(相当于其他语言的接口)。 也就是说,不是所有类型都可以比较大小,只有实现了这个 trait 的类型才可以比较大小。 后面会学习在泛型类型参数中指定特定的 trait。struct 定义中的泛型
struct Point<T> {x: T,y: T,}fn main() {let integer = Point { x: 5, y: 10 };let float = Point { x: 1.0, y: 4.0 };}如何让 x 和 y 是不同类型的呢?
struct Point<T, U> {x: T,y: U,}fn main() {let integer = Point { x: 5, y: 10 };let float = Point { x: 1, y: 4.0 };}这样既可以是不同的类型,也可以是相同的类型。
可以使用多个泛型的类型参数
可以让枚举的变体持有泛型数据类型
为 struct 或 enum 实现方法的时候,可以在定义中使用泛型。
struct Point<T> {x: T,y: T,}impl<T> Point<T> {fn x(&self) -> &T {&self.x}}// 针对具体的类型实现方法impl Point<i32> {fn x1(&self) -> &i32 {&self.x}}fn main() {let p = Point { x: 5, y: 10 };println!("p.x = {}", p.x);}
注意:
- 把 T 放在 impl 关键字后,表示在类型 T 上实现方法
- 例如:
impl<T> Point<T>
- 例如:
- 只针对具体类型实现方法(其余类型没实现方法)
- 例如:
impl Point<i32>
- 例如:
struct 里的泛型类型参数可以和方法的泛型类型参数不同
struct Point<T, U> {x: T,y: U,}impl<T, U> Point<T, U> {fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {Point {x: self.x,y: other.y,}}}fn main() {let p1 = Point { x: 5, y: 4 };let p2 = Point { x: "Hello", y: 'c' };let p3 = p1.mixup(p2);println!("p3.x = {}, p3.y = {}", p3.x, p3.y); // p3.x = 5, p3.y = c}
泛型代码的性能
- 把 T 放在 impl 关键字后,表示在类型 T 上实现方法
使用泛型的代码和使用具体类型的代码运行速度是一样的。
- 单态化 (monomorphization):
- 在编译时将泛型替换为具体类型的过程
编译时转换为具体类型,如下 ```rust enum Option_i32 { Some(i32), None, }fn main() {let integer = Some(5); // std::option::Option<i32>let float = Some(5.0); // std::option::Option<f64>}
- 在编译时将泛型替换为具体类型的过程
enum Option_f64 { Some(f64), None, }
fn main() { let integer = Option_i32::Some(5); let float = Option_f64::Some(5.0); } ```
