Rust 中的泛型

  • 使用泛型作为函数的类型参数
  • 泛型作为结构体的成员类型
  • Traits:定义共享行为
  • 特征绑定

泛型作为函数的类型参数

  • 一个函数,接收两个数字,返回较大的,数字可以是u32, f32 … ```rust // PartialOrd 为 T 的特征 (Trait) fn largest(a: T, b: T) -> T { if a > b {
    1. a
    } else {
    1. b
    } }

fn main() { println!(“{}”, largest(10, 11)); println!(“{}”, largest(10.0, 12.0)); }

  1. <a name="WV4M5"></a>
  2. # 结构体中的泛型
  3. - 可以用泛型语法定义结构体
  4. - 一个结构体可以有多个泛型参数,但是一般建议拆分结构体,使一个结构体只使用一个泛型参数
  5. ```rust
  6. struct Point<T, U> {
  7. x: T,
  8. y: T,
  9. z: U
  10. }
  11. let p1 = Point { x: 5, y: 10, z: 10.0 };
  12. let p2 = Point { x: 5.0, y: 10.0, z: 11 };

结构体泛型的实现

  • 需要在impl后加,并且在struct名称后面加 ```rust struct Point { x: T, y: T, }

impl Point {}

fn main() {}

  1. - impl 下的方法中使用泛型
  2. ```rust
  3. struct Point<T> {
  4. x: T,
  5. y: T,
  6. }
  7. impl<T: std::cmp::PartialOrd + Clone> Point<T> {
  8. fn largest(&self) -> T {
  9. if self.x > self.y {
  10. self.x.clone()
  11. } else {
  12. self.y.clone()
  13. }
  14. }
  15. }
  16. // 某种特定类型才有的方法
  17. impl Point<f32> {
  18. fn distance_from_orgin(&self) -> f32 {
  19. (self.x.powi(2) + self.y.powi(2)).sqrt()
  20. }
  21. }

使用 Traits 定义共同行为

定义共同行为

  • 某一类数据可能含有一些共同行为:比如都能被显示在屏幕上,或者相互间可以比较大小等
  • 我们将这种共同行为称为 Traits
  • 比如标准库的 std::fmt::Display找个Traits,实现了在 Formatter 中使用空白格式{}的功能
    1. pub trait Display {
    2. pub fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>
    3. }
    ```rust use std::fmt;

struct Point { x: i32, y: i32, }

impl fmt::Display for Point { fn fmt(&self, f: &mut fmt::Formatter<’_>) -> fmt::Result { write!(f, “({}, {})”, self.x, self.y) } }

fn main() { let p = Point { x: 0, y: 1 }; assert_eq!(format!(“the point is: {}”, p), “the point is: (0, 1)”); println!(“{}”, p); }

  1. <a name="SkTg3"></a>
  2. ## 作为参数类型
  3. - 两种写法:泛型函数、语法糖
  4. ```rust
  5. use std::fmt;
  6. struct Point {
  7. x: i32,
  8. y: i32,
  9. }
  10. impl fmt::Display for Point {
  11. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  12. write!(f, "({}, {})", self.x, self.y)
  13. }
  14. }
  15. // 1. 泛型函数
  16. fn show<T: fmt::Display>(a: T) {
  17. println!("show: {}", a);
  18. }
  19. // 语法糖
  20. fn show2(a: impl fmt::Display) {
  21. println!("show: {}", a);
  22. }
  23. fn main() {
  24. let p = Point { x: 0, y: 1 };
  25. // show(p);
  26. show2(p);
  27. }
  28. use std::fmt;
  29. struct Point {
  30. x: i32,
  31. y: i32,
  32. }
  33. impl fmt::Display for Point {
  34. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  35. write!(f, "({}, {})", self.x, self.y)
  36. }
  37. }
  38. // 1. 泛型函数
  39. fn show<T: fmt::Display>(a: T) {
  40. println!("show: {}", a);
  41. }
  42. // 2. 语法糖
  43. fn show2(a: impl fmt::Display) {
  44. println!("show: {}", a);
  45. }
  46. fn main() {
  47. let p = Point { x: 0, y: 1 };
  48. // show(p);
  49. show2(p);
  50. }

自动派生

  • Rust 编译器可以自动为我们的结构体实现也写Traits,这种自动化技术被称为派生
  • 比如在编写代码时常见的一个需求:将结构体输出到屏幕,除了手动impl Display,也可以使用自动派生技术让Rust编译器自动帮您添加代码:

    1. // Debug Trait 将允许数据结构使用 {:?} 格式进行格式化
    2. #[derive(Debug)]
    3. struct Point {
    4. x: i32,
    5. y: i32,
    6. }
    7. let p = Point { x: 0, y: 1 };
    8. println!("{:?}", p);
  • 自动派生的一个前提:该结构体的全部字段都实现了指定的 Trait

    • 比如上面例子 i32 就已经实现了Debug Trait
  • 可以使用多个派生 ```rust // PartialEq 允许两个数据使用 == 进行比较 // Default 支持default创建

    [derive(Debug, PartialEq, Default)]

    struct Point { x: i32, y: i32, }

fn main() { let p1 = Point { x: 0, y: 1 }; let p2 = Point { x: 0, y: 1 }; let p3 = Point::default(); println!(“{:?}”, p1); // Point { x: 0, y: 1 } println!(“{:?}”, p2); // Point { x: 0, y: 1 } println!(“{:?}”, p3); // Point { x: 0, y: 0 } println!(“p1 == p2: {}”, p1 == p2); // p1 == p2: true println!(“p1 == p3: {}”, p1 == p3); // p1 == p3: false }

```