## 泛型数据类型

ch10-01-syntax.md
commit af34ac954a6bd7fc4a8bbcc5c9685e23c5af87da

### 在函数定义中使用泛型

fn largest_i32(list: &[i32]) -> i32 {
let mut largest = list[0];

for &item in list.iter() {
if item > largest {
largest = item;
}
}

largest
}

fn largest_char(list: &[char]) -> char {
let mut largest = list[0];

for &item in list.iter() {
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);
assert_eq!(result, 100);

let char_list = vec!['y', 'm', 'a', 'q'];

let result = largest_char(&char_list);
println!("The largest char is {}", result);
assert_eq!(result, 'y');
}


largest_i32 函数是从示例 10-3 中摘出来的，它用来寻找 slice 中最大的 i32largest_char 函数寻找 slice 中最大的 char。因为两者函数体的代码是一样的，我们可以定义一个函数，再引进泛型参数来消除这种重复。

fn largest<T>(list: &[T]) -> T {


fn largest<T>(list: &[T]) -> T {
let mut largest = list[0];

for &item in list.iter() {
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);
}


error[E0369]: binary operation > cannot be applied to type T
--> src/main.rs:5:12
|
5 |         if item > largest {
|            ^^^^^^^^^^^^^^
|
= note: an implementation of std::cmp::PartialOrd might be missing for T


### 结构体定义中的泛型

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 };
}


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

fn main() {
let wont_work = Point { x: 5, y: 4.0 };
}


error[E0308]: mismatched types
--> src/main.rs:7:38
|
7 |     let wont_work = Point { x: 5, y: 4.0 };
|                                      ^^^ expected integer, found
floating-point number
|
= note: expected type {integer}
found type {float}


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

fn main() {
let both_integer = Point { x: 5, y: 10 };
let both_float = Point { x: 1.0, y: 4.0 };
let integer_and_float = Point { x: 5, y: 4.0 };
}


### 枚举定义中的泛型


#![allow(unused)]
fn main() {
enum Option<T> {
Some(T),
None,
}
}



#![allow(unused)]
fn main() {
enum Result<T, E> {
Ok(T),
Err(E),
}
}


Result 枚举有两个泛型类型，TEResult 有两个成员：Ok，它存放一个类型 T 的值，而 Err 则存放一个类型 E 的值。这个定义使得 Result 枚举能很方便的表达任何可能成功（返回 T 类型的值）也可能失败（返回 E 类型的值）的操作。实际上，这就是我们在示例 9-3 用来打开文件的方式：当成功打开文件的时候，T 对应的是 std::fs::File 类型；而当打开文件出现问题时，E 的值则是 std::io::Error 类型。

### 方法定义中的泛型

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

impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}

fn main() {
let p = Point { x: 5, y: 10 };

println!("p.x = {}", p.x());
}



#![allow(unused)]
fn main() {
struct Point<T> {
x: T,
y: T,
}

impl Point<f32> {
fn distance_from_origin(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
}


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: 10.4 };
let p2 = Point { x: "Hello", y: 'c'};

let p3 = p1.mixup(p2);

println!("p3.x = {}, p3.y = {}", p3.x, p3.y);
}


main 函数中，定义了一个有 i32 类型的 x（其值为 5）和 f64y（其值为 10.4）的 Pointp2 则是一个有着字符串 slice 类型的 x（其值为 "Hello"）和 char 类型的 y（其值为c）的 Point。在 p1 上以 p2 作为参数调用 mixup 会返回一个 p3，它会有一个 i32 类型的 x，因为 x 来自 p1，并拥有一个 char 类型的 y，因为 y 来自 p2println! 会打印出 p3.x = 5, p3.y = c

### 泛型代码的性能

Rust 通过在编译时进行泛型代码的 单态化monomorphization）来保证效率。单态化是一个通过填充编译时使用的具体类型，将通用代码转换为特定代码的过程。


#![allow(unused)]
fn main() {
let integer = Some(5);
let float = Some(5.0);
}


enum Option_i32 {
Some(i32),
None,
}

enum Option_f64 {
Some(f64),
None,
}

fn main() {
let integer = Option_i32::Some(5);
let float = Option_f64::Some(5.0);
}