很多编程语言都支持泛型的特性,泛型是对具体类型或属性的抽象替代,可以实现在编写代码和编译代码时无需知道其在运行时具体类型的特性。 rust也是支持泛型的,而且rust中使用泛型的代码相比使用具体类型的代码几乎没有任何性能上的损耗,rust在编译时使会进行泛型代码的Monomorphization来保障效率。 Monomorphization会在编译时填充需要使用的具体类型,将通用代码转换回特定类型的代码。

函数定义中参数和返回值的泛型

在函数定义中函数的参数和返回值的类型可以使用泛型表示。 在函数定义中函数名称后边的尖括号<>中声明泛型参数的名称后,就可以对函数定义的函数参数和返回值使用泛型类型。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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);
}

结构体定义中的泛型

在结构体定义中结构体名称后边的尖括号<>中声明泛型参数的名称后,就可以在结构体定义中的其他地方使用泛型类型。

rustlings中关于泛型结构体的练习在exercises/generics/generics2.rsexercises/generics/generics3.rs中。

exercises/generics/generics2.rs:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
struct Wrapper<T> {
    value: T,
}

impl<T> Wrapper<T> {
    pub fn new(value: T) -> Self {
        Wrapper { value }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn store_u32_in_wrapper() {
        assert_eq!(Wrapper::new(42).value, 42);
    }

    #[test]
    fn store_str_in_wrapper() {
        assert_eq!(Wrapper::new("Foo").value, "Foo");
    }
}

注意在结构体方法的定义中使用泛型时,必须在impl后面声明T,这样就可以在Wrapper<T>的方法中使用它了。在impl后边声明泛型T是告诉rust Wrapper<T>中的T类型是泛型而不是具体类型。

exercises/generics/generics3.rs:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
pub struct ReportCard<T> {
    pub grade: T,
    pub student_name: String,
    pub student_age: u8,
}

impl<T: std::fmt::Display> ReportCard<T> {
    pub fn print(&self) -> String {
        format!("{} ({}) - achieved a grade of {}",
            &self.student_name, &self.student_age, &self.grade)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn generate_numeric_report_card() {
        let report_card = ReportCard {
            grade: 2.1,
            student_name: "Tom Wriggle".to_string(),
            student_age: 12,
        };
        assert_eq!(
            report_card.print(),
            "Tom Wriggle (12) - achieved a grade of 2.1"
        );
    }

    #[test]
    fn generate_alphabetic_report_card() {
        // TODO: Make sure to change the grade here after you finish the exercise.
        let report_card = ReportCard {
            grade: "A+".to_owned(),
            student_name: "Gary Plotter".to_string(),
            student_age: 11,
        };
        assert_eq!(
            report_card.print(),
            "Gary Plotter (11) - achieved a grade of A+"
        );
    }
}

枚举定义中的泛型

rust的枚举成员中也可以存放泛型数据类型。 例如rust中常用的两个枚举Option和Result。

1
2
3
4
5
6
7
8
9
enum Option<T> {
    Some(T),
    None,
}

enum Result<T, E> {
    Ok(T),
    Err(E),
}

参考