提取函数消除重复
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>
### 函数定义中的泛型
- 泛型函数:
- 参数类型
- 返回类型
替换成字符类型的切片
```rust
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(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 error
For 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); } ```