Rust标准库涉及的Trait

本篇文章是对下面文章的阅读笔记,不保证可靠性,希望大家还是以Rust标准库源码/英文原文为准

Tour of Rust’s Standard Library Traits

本文亦参考了下面这篇文章,但该文章排版有混乱的地方
Tour of Rust’s Standard Library Traits中译

Trait基础

1. Self指代实现的类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
trait Trait {
// always returns i32
fn returns_num() -> i32;

// returns implementing type
fn returns_self() -> Self;
}

struct SomeType;
struct OtherType;

impl Trait for SomeType {
fn returns_num() -> i32 {
5
}

// Self == SomeType
fn returns_self() -> Self {
SomeType
}
}

2. Function

  1. 指代第一个参数不是self的任意函数,类似其他语言的静态函数
  2. 只能通过 Typename::func() 方式调用。这里的type实现了trait

3. Method

  1. 指的是第一个参数是self的函数。其类型是 Self , &Self或 &mut Self。也可以被Box,Rc,Arc或Pin来包装。

  2. 通过 TraitName::func() 方式调用,或者 <实现trait类型的实例>.func() 调用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    fn main() {
    let five = ToString::to_string(&5);
    let five = i32::to_string(&5);
    }
    // 5这里是i32类型,i32类型实现了ToString trait
    // https://doc.rust-lang.org/std/string/trait.ToString.html
    fn main() {
    let five = 5.to_string();
    }

4. Associated Types 关联类型

  1. 每个类型对这个trait的实现中,可以由实现者指定func中某个参数的类型

    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
    trait Trait {
    type AssociatedType;
    fn func(arg: Self::AssociatedType);
    }

    struct SomeType;
    struct OtherType;

    // any type implementing Trait can
    // choose the type of AssociatedType

    impl Trait for SomeType {
    type AssociatedType = i8; // chooses i8
    fn func(arg: Self::AssociatedType) {}
    }

    impl Trait for OtherType {
    type AssociatedType = u8; // chooses u8
    fn func(arg: Self::AssociatedType) {}
    }

    fn main() {
    SomeType::func(-1_i8); // can only call func with i8 on SomeType
    OtherType::func(1_u8); // can only call func with u8 on OtherType
    }

5. Generic Parameters 泛型参数

  1. “泛型参数”泛指

    1. 泛型类型参数(generic type parameters)
    2. 泛型生命周期参数(generic lifetime parameters)
    3. 泛型常量参数(generic const parameters)
  2. 因为这些说起来比较拗口,所以人们通常把它们简称为 “泛型类型(generic type)”、“生命周期(lifetime)”和 “泛型常量(generic const)”。

  3. 本文不讨论泛型常量

  4. 一个泛型类型 + 生命周期的例子,可以通过<T = i32> 的方式赋默认类型

    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
    // trait declaration generalized with lifetime & type parameters
    trait Trait<'a, T> {
    // signature uses generic type
    fn func1(arg: T);

    // signature uses lifetime
    fn func2(arg: &'a i32);

    // signature uses generic type & lifetime
    fn func3(arg: &'a T);
    }

    struct SomeType;

    impl<'a> Trait<'a, i8> for SomeType {
    fn func1(arg: i8) {}
    fn func2(arg: &'a i32) {}
    fn func3(arg: &'a i8) {}
    }

    impl<'b> Trait<'b, u8> for SomeType {
    fn func1(arg: u8) {}
    fn func2(arg: &'b i32) {}
    fn func3(arg: &'b u8) {}
    }

    // any type can be used as the default
    trait Trait2<T = i32> {
    fn func2(t: T) {}
    }
  5. 也可以只对trait中的单个函数/方法泛型化

    1
    2
    3
    trait Trait {
    fn func<'a, T>(t: &'a T);
    }

6. 泛型 vs 关联类型

相同点:

  • 都把在 trait 的函数和方法中使用哪种具体类型的决定权交给了实现者

不同点:

  • 当每个类型只应该有 trait 的一个实现时,使用关联类型。
  • 当每个类型可能会有 trait 的多个实现时,使用泛型类型。
  1. 一个例子 Point 类型实现了Add这个trait,目前实现采用了关联类型,因此只能实现对一个类型的add func 实现Point类型对i32类型的add 方法会报错
    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
    46
    trait Add {
    type Rhs;
    type Output;
    fn add(self, rhs: Self::Rhs) -> Self::Output;
    }

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

    impl Add for Point {
    type Rhs = Point;
    type Output = Point;
    fn add(self, rhs: Point) -> Point {
    Point {
    x: self.x + rhs.x,
    y: self.y + rhs.y,
    }
    }
    }

    impl Add for Point { // ❌
    type Rhs = i32;
    type Output = Point;
    fn add(self, rhs: i32) -> Point {
    Point {
    x: self.x + rhs,
    y: self.y + rhs,
    }
    }
    }

    fn main() {
    let p1 = Point { x: 1, y: 1 };
    let p2 = Point { x: 2, y: 2 };
    let p3 = p1.add(p2);
    assert_eq!(p3.x, 3);
    assert_eq!(p3.y, 3);

    let p1 = Point { x: 1, y: 1 };
    let int2 = 2;
    let p3 = p1.add(int2); // ❌
    assert_eq!(p3.x, 3);
    assert_eq!(p3.y, 3);
    }
    所以这里需要使用泛型来支持“多个类型在trait中的func会有多个实现“ 这里output也是关联类型,因此所有func实现的Output只能是一个类型 如果实现“点 + 点 = 线段”这种其他Output类型,则会报错。解决方法就是把Output也换成泛型
    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
    trait Add<Rhs> {
    type Output;
    fn add(self, rhs: Rhs) -> Self::Output;
    }

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

    impl Add<Point> for Point {
    type Output = Self;
    fn add(self, rhs: Point) -> Self::Output {
    Point {
    x: self.x + rhs.x,
    y: self.y + rhs.y,
    }
    }
    }

    impl Add<i32> for Point { // ✅
    type Output = Self;
    fn add(self, rhs: i32) -> Self::Output {
    Point {
    x: self.x + rhs,
    y: self.y + rhs,
    }
    }
    }

    fn main() {
    let p1 = Point { x: 1, y: 1 };
    let p2 = Point { x: 2, y: 2 };
    let p3 = p1.add(p2);
    assert_eq!(p3.x, 3);
    assert_eq!(p3.y, 3);

    let p1 = Point { x: 1, y: 1 };
    let int2 = 2;
    let p3 = p1.add(int2); // ✅
    assert_eq!(p3.x, 3);
    assert_eq!(p3.y, 3);
    }

7. 作用域

  1. Trait 只有被显式地导入,才能使用其中定义的func

    比如Read trait就需要导入才能用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    use std::fs::File;
    use std::io;
    use std::io::Read; // ✅

    fn main() -> Result<(), io::Error> {
    let mut file = File::open("Cargo.toml")?;
    let mut buffer = String::new();
    file.read_to_string(&mut buffer)?; // ✅
    Ok(())
    }
  2. 标准库预置是个例外,总是被隐式导入。(The standard library prelude)是标准库中的一个模块,也就是说,std::prelude::v1,它在每个其他模块的顶部被自动导入,即use std::prelude::v1::*。这样的话,下面这些 trait 就总会在作用域中,我们不需要自己显式地导入它们,因为它们是预置的一部分。

    • AsMut
    • AsRef
    • Clone
    • Copy
    • Default
    • Drop
    • Eq
    • Fn
    • FnMut
    • FnOnce
    • From
    • Into
    • ToOwned
    • IntoIterator
    • Iterator
    • PartialEq
    • PartialOrd
    • Send
    • Sized
    • Sync
    • ToString
    • Ord

8. 派生宏(Derive Macros)

标准库导出了一小部分派生宏,这么派生宏可以让我们可以便捷地在一个类型上实现 trait,前提是该类型的所有成员都实现了这个 trait。派生宏以它们所实现的 trait 来命名。

  • Clone
  • Copy
  • Debug
  • Default
  • Eq
  • Hash
  • Ord
  • PartialEq
  • PartialOrd
1
2
3
// macro derives Copy & Clone impl for SomeType
#[derive(Copy, Clone)]
struct SomeType;

9. Default impls 默认实现

  1. trait可以为定义的函数/方法提供默认实现

    标准库中的很多 trait 为很多它们的方法提供了默认实现。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    trait Trait {
    fn method(&self) {
    println!("default impl");
    }
    }

    struct SomeType;
    struct OtherType;

    // use default impl for Trait::method
    impl Trait for SomeType {}

    impl Trait for OtherType {
    // use our own impl for Trait::method
    fn method(&self) {
    println!("OtherType impl");
    }
    }

    fn main() {
    SomeType.method(); // prints "default impl"
    OtherType.method(); // prints "OtherType impl"
    }

10. Generic Blanket Impls 泛型覆盖实现

  1. trait中的方法/函数可以定义一个泛型实现
    1. 一个例子

      1. 类型T满足Rem<Output = T> + PartialEq<T> + Sized, 且类型u8可以转换为类型T
      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
      #![allow(unused)]
      fn main() {
      use std::fmt::Debug;
      use std::convert::TryInto;
      use std::ops::Rem;

      trait Even {
      fn is_even(self) -> bool;
      }

      // generic blanket impl
      impl<T> Even for T
      where
      T: Rem<Output = T> + PartialEq<T> + Sized,
      u8: TryInto<T>,
      <u8 as TryInto<T>>::Error: Debug,
      {
      fn is_even(self) -> bool {
      // these unwraps will never panic
      self % 2.try_into().unwrap() == 0.try_into().unwrap()
      }
      }

      #[test] // ✅
      fn test_is_even() {
      assert!(2_i8.is_even());
      assert!(4_u8.is_even());
      assert!(6_i16.is_even());
      // etc
      }
      }
    2. 泛型覆盖实现提供了方法的实现,所以它们不能被重写。

      trait 一致性是指,对于任意给定的类型,最多存在某一 trait 的一个实现。Rust 用来强制执行特质一致性的规则,这些规则的含义,以及针对这些含义的变通方案都不在本文的讨论范围之内。

11. Subtraits & Supertraits

子集、超集

  1. 考虑如下的例子

    1. 所有实现了Subtrait的类型是所有实现了Supertrait的类型的子集,或者反过来讲:所有实现了Supertrait的类型是所有实现了Subtrait类型的子集。
    1
    trait Subtrait: Supertrait {}

    它等于

    1
    trait Subtrait where Self: Supertrait {}
  2. 子集和超集说的是的是实现trait的类型:

    1. 也就是说约束在Self上:实现Subtrait的类型
    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
    trait Supertrait {
    fn method(&self) {
    println!("in supertrait");
    }
    }

    trait Subtrait: Supertrait {
    // this looks like it might impl or
    // override Supertrait::method but it
    // does not
    fn method(&self) {
    println!("in subtrait")
    }
    }

    struct SomeType;

    // adds Supertrait::method to SomeType
    impl Supertrait for SomeType {}

    // adds Subtrait::method to SomeType
    impl Subtrait for SomeType {}

    // both methods exist on SomeType simultaneously
    // neither overriding or shadowing the other

    fn main() {
    SomeType.method(); // ❌ ambiguous method call
    // must disambiguate using fully-qualified syntax
    <SomeType as Supertrait>::method(&st); // ✅ prints "in supertrait"
    <SomeType as Subtrait>::method(&st); // ✅ prints "in subtrait"
    }
  3. 需要区分:对泛型进行约束

    1. 下面例子中,t的类型T一定实现了Clone Trait,或者说“类型T依赖Clone trait”,称为:泛型依赖于 trait 约束。

      1. 在function中,t.clone() 可以被调用(定义在Clone trait的func都可以被调用)
      1
      2
      3
      fn function<T: Clone>(t: T) {
      // impl
      }
  4. 子集和超集

    1. Copy Trait 的例子

      1. Copy是Clone的子集,Copy并不依赖Clone

        1
        trait Copy: Clone {}
    2. 可以这么理解:subtrait 细化(refine)了它们的 supertrait。

      “细化(Refinement)”刻意保持一定的模糊性,因为它们在不同的上下文环境中会有不同的含义:

      • subtrait 可能会使得 supertrait 的方法实现更为具体,快速,占用更少的内存,例如,Copy:Clone
      • subtrait 可能会对 supertrait 的方法实现增加额外的保证,例如:Eq: PartialEq,Ord: PartialOrd,ExactSizeIterator: Iterator;
      • subtrait 可能会使得 supertrait 的方法更为灵活和易于调用,例如:FnMut: FnOnce,Fn: FnMut;
      • subtrait 可能会扩展 supertrait 并添加新的方法,例如:DoubleEndedIterator: Iterator,ExactSizeIterator: Iterator

    感觉这里的“细化”可以理解为“特例化” zelin 220513

12. Trait对象

  1. 泛型可以实现编译期多态,Trait对象可以实现运行时多态

  2. 一个使用trait对象是函数动态返回不同类型的例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    fn example(condition: bool, vec: Vec<i32>) -> Box<dyn Iterator<Item = i32>> {
    let iter = vec.into_iter();
    if condition {
    // Has type:
    // Box<Map<IntoIter<i32>, Fn(i32) -> i32>>
    // But is cast to:
    // Box<dyn Iterator<Item = i32>>
    Box::new(iter.map(|n| n * 2))
    } else {
    // Has type:
    // Box<Filter<IntoIter<i32>, Fn(&i32) -> bool>>
    // But is cast to:
    // Box<dyn Iterator<Item = i32>>
    Box::new(iter.filter(|&n| n >= 2))
    }
    }
  3. 一个使用trait对象在集合中存储不同类型的例子

    这些类型都实现了同一个trait

    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
    #![allow(unused)]
    fn main() {
    use std::f64::consts::PI;

    struct Circle {
    radius: f64,
    }

    struct Square {
    side: f64
    }

    trait Shape {
    fn area(&self) -> f64;
    }

    impl Shape for Circle {
    fn area(&self) -> f64 {
    PI * self.radius * self.radius
    }
    }

    impl Shape for Square {
    fn area(&self) -> f64 {
    self.side * self.side
    }
    }

    fn get_total_area(shapes: Vec<Box<dyn Shape>>) -> f64 {
    shapes.into_iter().map(|s| s.area()).sum()
    }

    fn example() {
    let shapes: Vec<Box<dyn Shape>> = vec![
    Box::new(Circle { radius: 1.0 }), // Box<Circle> cast to Box<dyn Shape>
    Box::new(Square { side: 1.0 }), // Box<Square> cast to Box<dyn Shape>
    ];
    assert_eq!(PI + 1.0, get_total_area(shapes)); // ✅
    }
    }
  4. Trait对象是没有大小的,所以必须用智能指针包裹trait对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    struct Struct;
    trait Trait {}

    // regular struct
    &Struct
    Box<Struct>
    Rc<Struct>
    Arc<Struct>

    // trait objects
    &dyn Trait
    Box<dyn Trait>
    Rc<dyn Trait>
    Arc<dyn Trait>
  5. 不是所有的 trait 都可以被转成 trait 对象。当且仅当一个 trait 满足下面这些要求时,它才是对象安全的(object-safe):

    • trait 不要求Self:Sized
    • trait 的所有方法都是对象安全的

    当一个 trait 方法满足下面的要求时,该方法是对象安全的:

    • 方法要求Self:Sized 或者
    • 方法在其接收者位置仅使用一个Self类型

13. Maker Traits

指的是没有trait item(项)的trait(即没有任何函数/方法)

仅仅是“标记”功能:类型具有“某种属性”

Eq就是一个标记Trait,在PartialEq基础上标记了“额外具有反射性”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Impling PartialEq for a type promises
// that equality for the type has these properties:
// - symmetry: a == b implies b == a, and
// - transitivity: a == b && b == c implies a == c
// But DOES NOT promise this property:
// - reflexivity: a == a
trait PartialEq {
fn eq(&self, other: &Self) -> bool;
}

// Eq has no trait items! The eq method is already
// declared by PartialEq, but "impling" Eq
// for a type promises this additional equality property:
// - reflexivity: a == a
trait Eq: PartialEq {}

// f64 impls PartialEq but not Eq because NaN != NaN
// i32 impls PartialEq & Eq because there's no NaNs :)

14. Auto Trait: 自动Trait

  1. 自动 Trait 是指如果一个类型的所有成员都实现了该 trait,该类型就会自动实现该 trait。

  2. “成员(member)”的含义取决于类型,例如:结构体的字段、枚举的变量、数组的元素、元组的项,等等

  3. 自动 trait 必须是标记 trait,但不是所有标记trait都是自动trait

  4. 自动trait的例子

    1
    2
    3
    4
    5
    // implemented for types which are safe to send between threads
    unsafe auto trait Send {}

    // implemented for types whose references are safe to send between threads
    unsafe auto trait Sync {}

15. unsafe Trait

  1. trait 可以被标记为unsafe,指的是实现trait的时候可以带一些unsafe代码

  2. Send Sync这两个Trait就是unsafe Trait。如果手动实现Send Sync这两个Trait的时候,需要加上unsafe

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // SomeType is not Send or Sync
    struct SomeType {
    not_send_or_sync: *const (),
    }

    // but if we're confident that our impl doesn't have any data
    // races we can explicitly mark it as Send and Sync using unsafe
    unsafe impl Send for SomeType {}
    unsafe impl Sync for SomeType {}

二、Auto Trait

1. Send & Sync

  1. 如果一个类型满足Send,说明该类型可以安全地在线程中发送(或者说移动)

  2. 如果一个类型满足Sync,说明该类型可以安全地在线程中共享引用

  3. In more precise terms some type T is Sync if and only if &T is Send.

    当且仅当&T类型满足Send Trait,T才满足Sync Trait

  4. 几乎所有的类型都满足Send、Sync

    1. Send Trait例外:Rc
      1. 线程安全的版本:Arc
    2. Sync Trait例外:Rc、Cell、RefCell
      1. 线程安全的Cell/RefCell : Mutex/RwLock
    3. 可以使用Mutex/Rwlock包装原始类型获得原子性,也可以使用标准库提供的:AtomBool之类的原子类型
  5. 即使没有任何内部同步的类型,由于Rust借用规则的保证,这个类型大概率格式满足Sync的

    1. 一个例子,多个线程只读共享&str 类型的 greeting_ref,
      1. 在不可变引用仍存在时,不允许出现可变引用。

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        use crossbeam::thread;

        fn main() {
        let mut greeting = String::from("Hello");
        let greeting_ref = &greeting;

        thread::scope(|scoped_thread| {
        // spawn 3 threads
        for n in 1..=3 {
        // greeting_ref copied into every thread
        scoped_thread.spawn(move |_| {
        println!("{} {}", greeting_ref, n); // prints "Hello {n}"
        });
        }

        // line below could cause UB or data races but compiler rejects it
        greeting += " world"; // ❌ cannot mutate greeting while immutable refs exist
        });

        // can mutate greeting after every thread has joined
        greeting += " world"; // ✅
        println!("{}", greeting); // prints "Hello world"
        }

    b. 也可以一个线程可写

    在一个可变引用存在的时候,不允许出现第二个可变引用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    use crossbeam::thread;

    fn main() {
    let mut greeting = String::from("Hello");
    let greeting_ref = &mut greeting;

    thread::scope(|scoped_thread| {
    // greeting_ref moved into thread
    scoped_thread.spawn(move |_| {
    *greeting_ref += " world";
    println!("{}", greeting_ref); // prints "Hello world"
    });

    // line below could cause UB or data races but compiler rejects it
    greeting += "!!!"; // ❌ cannot mutate greeting while mutable refs exist
    });

    // can mutate greeting after the thread has joined
    greeting += "!!!"; // ✅
    println!("{}", greeting); // prints "Hello world!!!"
    }

    2. Sized

    1. 如果一个类型是Sized,这意味着它的类型大小在编译期是可知的,并且可以在栈上创建一个该类型的实例。

    2. 所有的泛型隐含了Sized Trait约束

      1
      2
      3
      4
      fn func<T>(t: &T) {}

      // example above desugared
      fn func<T: Sized>(t: &T) {}
    3. 因为所有的泛型类型上都有一个隐含的Sized约束,如果我们想要选择松弛这个约束,我们需要使用特定的“宽松约束(relaxed bound)”语法——?Sized,该语法目前只为Sized trait 存在。

      1
      2
      // now T can be unsized
      fn func<T: ?Sized>(t: &T) {}
    4. 所有的Trait隐含了?size 的约束

      1
      2
      3
      4
      trait Trait {}

      // example above desugared
      trait Trait: ?Sized {}

三、General Traits

1. Default

  1. 可以为实现Default的类型构造默认值

    1. 注意default函数没有self参数,因为其功能就是创造一个类型实例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    struct Color {
    r: u8,
    g: u8,
    b: u8,
    }

    impl Default for Color {
    // default color is black
    fn default() -> Self {
    Color {
    r: 0,
    g: 0,
    b: 0,
    }
    }
    }
    // 默认值构造
    fn main() {
    // just give me some color!
    let color = Color::default();
    }
  2. default函数也可以用在泛型类型中

    1
    2
    3
    4
    5
    6
    fn guarantee_length<T: Default>(mut vec: Vec<T>, min_len: usize) -> Vec<T> {
    for _ in 0..min_len.saturating_sub(vec.len()) {
    vec.push(T::default());
    }
    vec
    }
  3. 也可以用派生宏的方式实现Default trait

    1
    2
    3
    4
    5
    6
    7
    8
    // default color is still black
    // because u8::default() == 0
    #[derive(Default)]
    struct Color {
    r: u8,
    g: u8,
    b: u8
    }

2. Clone

预备知识

  1. Self指代实现的类型

  2. Methods指对类型实例操作的函数

  3. Default Impls 指Trait定义中可以包含函数/方法的默认实现

  4. Derive Macros 派生宏 指的是类型定义的时候可以通过派生宏的方式实现一个Trait

  5. Clone trait中包含两个函数

    1
    2
    3
    4
    5
    6
    trait Clone {
    fn clone(&self) -> Self;

    // provided default impls
    fn clone_from(&mut self, source: &Self);
    }
  6. Clone Trait的作用是,从一个不可变引用,转换为所拥有的值。即&T->T。

    1. Clone不保证这种转换的效率,所以它会很慢并且成本较高。
  7. 可以通过派生宏快速实现Clone Trait

    1. 下面的例子中两种实现是等价的
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #[derive(Clone)]
    struct SomeType {
    cloneable_member1: CloneableType1,
    cloneable_member2: CloneableType2,
    // etc
    }

    // macro generates impl below
    impl Clone for SomeType {
    fn clone(&self) -> Self {
    SomeType {
    cloneable_member1: self.cloneable_member1.clone(),
    cloneable_member2: self.cloneable_member2.clone(),
    // etc
    }
    }
    }

3. Copy

预备知识

  1. 标记Trait

  2. 子集和超集

  3. 派生宏

  4. Copy Trait

    1. 定义

      1
      trait Copy: Clone {}
    2. 作用

      按位拷贝,即T -> T

    3. 实现

      只能通过派生宏实现,下面的两个实现是等价的

      1
      2
      #[derive(Copy, Clone)]
      struct SomeType;
  5. Copy是Clone的子集:如果一个类型实现了Copy,那么这个类型自然满足Clone

    1
    2
    3
    4
    5
    6
    7
    // this is what the derive macro generates
    impl<T: Copy> Clone for T {
    // the clone method becomes just a copy
    fn clone(&self) -> Self {
    *self
    }
    }
  6. 一个类型如果实现了Copy,它在被移动(move)时的行为就发生了改变。默认情况下,所有的类型都有移动(move)语义 ,但是一旦某个类型实现了Copy,它就有了拷贝(copy)语义 。

    1. 一个例子,第一种情况下发生“移动”:src在移动后不可用。第二种情况发生“拷贝”:src在拷贝后仍有效

      1
      2
      3
      4
      5
      // a "move", src: !Copy
      let dest = src;

      // a "copy", src: Copy
      let dest = src;
    2. Vec<> 类型只能移动,不能拷贝

      1. Vec类型如下

        1
        { data: *mut [i32], length: usize, capacity: usize }
      2. 如果允许Copy的话

        src和dest就都有了数据的可变引用,这不满足Rust借用器检查

        1
        2
        src = { data: *mut [i32], length: usize, capacity: usize }
        dest = { data: *mut [i32], length: usize, capacity: usize }
    3. Option<>类型也可以实现拷贝

      1
      { is_valid: bool, data: i32 }

      拷贝后

      1
      2
      src = { is_valid: bool, data: i32 }
      dest = { is_valid: bool, data: i32 }
  7. 需要注意:Copy trait需要程序员显式地实现。

4. Any

  1. 预备知识

    1. 泛型覆盖实现,Trait定义的函数中,参数重满足一些Trait的类型,提供默认实现
  2. Any Trait作用:实现“多态”的需求

    1. 一个例子,从dyn Any类型中取出类型T需要使用downcast_ref::<T>() 和 downcast_mut::<T>()
      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
      use std::any::Any;

      #[derive(Default)]
      struct Point {
      x: i32,
      y: i32,
      }

      impl Point {
      fn inc(&mut self) {
      self.x += 1;
      self.y += 1;
      }
      }

      fn map_any(mut any: Box<dyn Any>) -> Box<dyn Any> {
      if let Some(num) = any.downcast_mut::<i32>() {
      *num += 1;
      } else if let Some(string) = any.downcast_mut::<String>() {
      *string += "!";
      } else if let Some(point) = any.downcast_mut::<Point>() {
      point.inc();
      }
      any
      }

      fn main() {
      let mut vec: Vec<Box<dyn Any>> = vec![
      Box::new(0),
      Box::new(String::from("a")),
      Box::new(Point::default()),
      ];
      // vec = [0, "a", Point { x: 0, y: 0 }]
      vec = vec.into_iter().map(map_any).collect();
      // vec = [1, "a!", Point { x: 1, y: 1 }]
      }
      但也可以通过参数化多态来实现多态 在大多数情况下,参数化多态要优于临时多态性,后者也可以用枚举(enum)来模拟,枚举具有更好的类型安全,需要的间接(抽象)也更少。
      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
      #[derive(Default)]
      struct Point {
      x: i32,
      y: i32,
      }

      impl Point {
      fn inc(&mut self) {
      self.x += 1;
      self.y += 1;
      }
      }

      enum Stuff {
      Integer(i32),
      String(String),
      Point(Point),
      }

      fn map_stuff(mut stuff: Stuff) -> Stuff {
      match &mut stuff {
      Stuff::Integer(num) => *num += 1,
      Stuff::String(string) => *string += "!",
      Stuff::Point(point) => point.inc(),
      }
      stuff
      }

      fn main() {
      let mut vec = vec![
      Stuff::Integer(0),
      Stuff::String(String::from("a")),
      Stuff::Point(Point::default()),
      ];
      // vec = [0, "a", Point { x: 0, y: 0 }]
      vec = vec.into_iter().map(map_stuff).collect();
      // vec = [1, "a!", Point { x: 1, y: 1 }]
      }
  3. Any Trait的实现

    不需要手动实现,均被“泛型覆盖实现”所覆盖

    Any trait中仅包含一个type_id函数,标准库的默认实现已经覆盖了所有类型

    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
    // https://doc.rust-lang.org/std/any/trait.Any.html
    #[stable(feature = "rust1", since = "1.0.0")]
    #[cfg_attr(not(test), rustc_diagnostic_item = "Any")]
    pub trait Any: 'static {
    /// Gets the `TypeId` of `self`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::any::{Any, TypeId};
    ///
    /// fn is_string(s: &dyn Any) -> bool {
    /// TypeId::of::<String>() == s.type_id()
    /// }
    ///
    /// assert_eq!(is_string(&0), false);
    /// assert_eq!(is_string(&"cookie monster".to_string()), true);
    /// ```
    #[stable(feature = "get_type_id", since = "1.34.0")]
    fn type_id(&self) -> TypeId;
    }

    #[stable(feature = "rust1", since = "1.0.0")]
    impl<T: 'static + ?Sized> Any for T {
    fn type_id(&self) -> TypeId {
    TypeId::of::<T>()
    }
    }

四、Formatting Trait

Trait Placeholder Description
Display {} display representation
Debug {:?} debug representation
Octal {:o} octal representation
LowerHex {:x} lowercase hex representation
UpperHex {:X} uppercase hex representation
Pointer {:p} memory address
Binary {:b} binary representation
LowerExp {:e} lowercase exponential representation
UpperExp {:E} uppercase exponential representation

1. Display Trait & ToString Trait

  1. Display trait

    1. 定义

      1
      2
      3
      trait Display {
      fn fmt(&self, f: &mut Formatter<'_>) -> Result;
      }
    2. 作用:用户定义的类型想格式化打印的时候可以实现Display trait

      比如给Point 类型实现Display trait,实现后类型的实例就可以在格式化输出中输出为字符串

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      use std::fmt;

      #[derive(Default)]
      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() {
      println!("origin: {}", Point::default());
      // prints "origin: (0, 0)"

      // get Point's Display representation as a String
      let stringified_point = format!("{}", Point::default());
      assert_eq!("(0, 0)", stringified_point); // ✅
      }
  2. ToString

    1. 定义

      1
      2
      3
      4
      5
      trait ToString {
      fn to_string(&self) -> String;
      }

      impl<T: Display + ?Sized> ToString for T;
    2. 所有实现Display Trait的类型都自动实现Tostring Trait(Again,泛型覆盖实现)

    3. 可以调用to_string 方法将对象转换为格式化打印

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      #[test] // ✅
      fn display_point() {
      let origin = Point::default();
      assert_eq!(format!("{}", origin), "(0, 0)");
      }

      #[test] // ✅
      fn point_to_string() {
      let origin = Point::default();
      assert_eq!(origin.to_string(), "(0, 0)");
      }

      #[test] // ✅
      fn display_equals_to_string() {
      let origin = Point::default();
      assert_eq!(format!("{}", origin), origin.to_string());
      }

2. Debug

  1. 定义

    1
    2
    3
    trait Debug {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result;
    }
  2. 实现Debug Trait:可以通过派生宏,也可以自己定义输出

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    #[derive(Debug)]
    struct Point {
    x: i32,
    y: i32,
    }

    // derive macro generates impl below
    impl fmt::Debug for Point {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    f.debug_struct("Point")
    .field("x", &self.x)
    .field("y", &self.y)
    .finish()
    }
    }
  3. dbg! 输出和 print! 输出的区别

    • dbg!打印到 stderr 而不是 stdout,因此在我们的程序中,能够很容易地和标准输出的输出结果区分。
    • dbg!会连同传入的表达式和表达式的计算结果一起打印出来。
    • dbg!会获取传入参数的所有权并将其返回,因此你可以在表达式中使用它:

五、Opertor Traits

Rust中所有操作符均有一个Trait与之对应

Trait(s) Category Operator(s) Description
Eq, PartialEq comparison == equality
Ord, PartialOrd comparison <, >, <=, >= comparison
Add arithmetic + addition
AddAssign arithmetic += addition assignment
BitAnd arithmetic & bitwise AND
BitAndAssign arithmetic &= bitwise assignment
BitXor arithmetic ^ bitwise XOR
BitXorAssign arithmetic ^= bitwise XOR assignment
Div arithmetic / division
DivAssign arithmetic /= division assignment
Mul arithmetic * multiplication
MulAssign arithmetic *= multiplication assignment
Neg arithmetic - unary negation
Not arithmetic ! unary logical negation
Rem arithmetic % remainder
RemAssign arithmetic %= remainder assignment
Shl arithmetic << left shift
ShlAssign arithmetic <<= left shift assignment
Shr arithmetic >> right shift
ShrAssign arithmetic >>= right shift assignment
Sub arithmetic - subtraction
SubAssign arithmetic -= subtraction assignment
Fn closure (…args) immutable closure invocation
FnMut closure (…args) mutable closure invocation
FnOnce closure (…args) one-time closure invocation
Deref other * immutable dereference
DerefMut other * mutable derenence
Drop other - type destructor
Index other [] immutable index
IndexMut other [] mutable index
RangeBounds other .. range

下面逐个介绍

1. Comparison Traits

Trait(s) Category Operator(s) Description
Eq, PartialEq comparison == equality
Ord, PartialOrd comparison <, >, <=, >= comparison
  1. PartialEq Trait

    1. 定义

      1
      2
      3
      4
      5
      6
      7
      8
      9
      trait PartialEq<Rhs = Self> 
      where
      Rhs: ?Sized,
      {
      fn eq(&self, other: &Rhs) -> bool;

      // provided default impls
      fn ne(&self, other: &Rhs) -> bool;
      }
    2. 作用

      满足PartialEq类型的实例可以通过==操作符检查是否和Rhs类型的实例相等。

    3. 特点

      1. PartialEq表示的是集合论中的:对称性、传递性
        • a == b也意味着b == a(对称性)
        • a == b && b == c 意味着 a == c (传递性)
    4. 实现

      1. 如果一个类型中所有成员均实现了PartialEq,那么这个类型的PartialEq Trait可以被派生宏实现
    5. 引用类型的实现

      1. again,由于”泛型覆盖实现”的特性,一旦一个类型满足了PartialEq trait,那么对应的引用类型的比较也自然被实现了,换句话说,该类型的引用类型也可以被比较了。

        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
        // this impl only gives us: Point == Point
        #[derive(PartialEq)]
        struct Point {
        x: i32,
        y: i32
        }

        // all of the generic blanket impls below
        // are provided by the standard library

        // this impl gives us: &Point == &Point
        impl<A, B> PartialEq<&'_ B> for &'_ A
        where A: PartialEq<B> + ?Sized, B: ?Sized;

        // this impl gives us: &mut Point == &Point
        impl<A, B> PartialEq<&'_ B> for &'_ mut A
        where A: PartialEq<B> + ?Sized, B: ?Sized;

        // this impl gives us: &Point == &mut Point
        impl<A, B> PartialEq<&'_ mut B> for &'_ A
        where A: PartialEq<B> + ?Sized, B: ?Sized;

        // this impl gives us: &mut Point == &mut Point
        impl<A, B> PartialEq<&'_ mut B> for &'_ mut A
        where A: PartialEq<B> + ?Sized, B: ?Sized;

      ii. 因为这个 trait 是泛型的,所以我们可以在不同的类型之间定义相等性(比较)。标准库利用这一点实现了类字符串类型之间的相互比较,比如String、&str、PathBuf、&Path、OsString、&OsStr等等。

  2. Eq Trait

    1. 定义

      是一个标记Trait,是PartialEq的子集

      1
      trait Eq: PartialEq<Self> {}
    2. 作用

      在PartialEq基础上要求“自反性”。也就是对于任意的a,都有a == a。

      从这种意义上来说,Eq对PartialEq进行了细化,因为它表示了一个更为严格的相等性。

    3. 实现

      如果一个类型的所有成员都实现了Eq,那么Eq的实现可以派生到这个类型。

      浮点型实现了PartialEq但是没有实现Eq,因为NaN != NaN。几乎所有其他的实现了PartialEq的类型都实现了Eq,除非它们包含浮点类型。

    4. 备注:一旦一个类型实现了PartialEq和Debug,我们可以就可以在assert_eq!宏中使用它。

      1. 还可以比较实现了PartialEq类型的集合。下面是一个例子

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        #[derive(PartialEq, Debug)]
        struct Point {
        x: i32,
        y: i32,
        }

        fn example_assert(p1: Point, p2: Point) {
        assert_eq!(p1, p2);
        }

        fn example_compare_collections<T: PartialEq>(vec1: Vec<T>, vec2: Vec<T>) {
        // if T: PartialEq this now works!
        if vec1 == vec2 {
        // some code
        } else {
        // other code
        }
        }

2. Hash Trait

  1. 定义

    1
    2
    3
    4
    5
    6
    trait Hash {
    fn hash<H: Hasher>(&self, state: &mut H);

    // provided default impls
    fn hash_slice<H: Hasher>(data: &[Self], state: &mut H);
    }
  2. 作用

    满足Hash Trait的类型可以被满足Hasher trait的的对象计算哈希值

    也就可以放在HashMap HashSet 的Key中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    use std::hash::Hasher;
    use std::hash::Hash;

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

    impl Hash for Point {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
    hasher.write_i32(self.x);
    hasher.write_i32(self.y);
    }
    }
  3. 实现

    可以通过派生宏实现

    1
    2
    3
    4
    5
    #[derive(Hash)]
    struct Point {
    x: i32,
    y: i32,
    }
  4. 特点

    1. 如果a == b那么a.hash() == b.hash()
    2. 如果一个类型的Eq Trait是派生宏实现的,Hash Trait也需要是被派生宏实现;或者二者可以均被手动实现。
      1. 但不要混合,因为可能会破坏“如果a == b那么a.hash() == b.hash()” 的保证

3. PartialOrd

  1. 定义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    enum Ordering {
    Less,
    Equal,
    Greater,
    }

    trait PartialOrd<Rhs = Self>: PartialEq<Rhs>
    where
    Rhs: ?Sized,
    {
    fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;

    // provided default impls
    fn lt(&self, other: &Rhs) -> bool;
    fn le(&self, other: &Rhs) -> bool;
    fn gt(&self, other: &Rhs) -> bool;
    fn ge(&self, other: &Rhs) -> bool;
    }
  2. 作用

    满足PartialOrd Trait的类型可以通过 </ ≤/ >/ ≥ 比较运算符和Rhs类型的实例比较大小

  3. 实现

    1. 如果一个类型的所有成员都实现了PartialOrd,那么它就可以被派生实现

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      #[derive(PartialEq, PartialOrd)]
      struct Point {
      x: i32,
      y: i32,
      }

      #[derive(PartialEq, PartialOrd)]
      enum Stoplight {
      Red,
      Yellow,
      Green,
      }
  4. 特点

    1. PartialOrd表示的是集合论的偏序

      https://zh.wikipedia.org/zh-cn/偏序关系

      集合中上的一个关系,这个关系对于集合中的部分元素具有反对称性+传递性,那么这个关系在这个集合上就是偏序(PartialOrder,局部序)的

      1. a < b implies !(a > b) (asymmetry) 反对称性
      2. a < b && b < c implies a < c (transitivity) 传递性
    2. PartialOrder Trait是PartialEq Trait的子集

      1. 二者的实现必须等价

        1
        2
        3
        fn must_always_agree<T: PartialOrd + PartialEq>(t1: T, t2: T) {
        assert_eq!(t1.partial_cmp(&t2) == Some(Ordering::Equal), t1 == t2);
        }
      2. PartialOrder Trait 是在PartialEq Trait上的“特例化/细化”

        满足PartialEq的类型只能比较相等/不等;满足PartialOrder的类型也可以比较相等/不相等,但是不等中还可以得出大于/小于的结论

    3. 派生宏实现的PartialOrder Trait,基于类型中成员变量的先后顺序比较的

      下面是个例子,前者先比较x,后者先比较y

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      // generates PartialOrd impl which orders
      // Points based on x member first and
      // y member second because that's the order
      // they appear in the source code
      #[derive(PartialOrd, PartialEq)]
      struct Point {
      x: i32,
      y: i32,
      }

      // generates DIFFERENT PartialOrd impl
      // which orders Points based on y member
      // first and x member second
      #[derive(PartialOrd, PartialEq)]
      struct Point {
      y: i32,
      x: i32,
      }

4. Ord

  1. 定义

    Ord Trait是Eq Trait和PartialOrder Trait的子集

    1
    2
    3
    4
    5
    6
    7
    8
    trait Ord: Eq + PartialOrd<Self> {
    fn cmp(&self, other: &Self) -> Ordering;

    // provided default impls
    fn max(self, other: Self) -> Self;
    fn min(self, other: Self) -> Self;
    fn clamp(self, min: Self, max: Self) -> Self;
    }
  2. 作用

    1. 比较大小、在两个实例中找最大、最小
    2. 一旦一个类型实现了Ord,我们就可以把它存储在BTreeMap和BTreeSet,还可以在 slice 上使用 sort()方法对其进行排序,这同样适用于其他可以解引用为 slice 的类型,比如数组、Vec和VecDeque。
  3. 实现

    1. 通过派生宏/手动实现

      这里注意,Ord Trait是PartialOrderTrait的子集,实现了Ord Trait后,PartialOrder的实现可以使用Ord Trait中的实现。

      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
      use std::cmp::Ordering;

      // of course we can use the derive macros here
      #[derive(Ord, PartialOrd, Eq, PartialEq)]
      struct Point {
      x: i32,
      y: i32,
      }

      // note: as with PartialOrd, the Ord derive macro
      // orders a type based on the lexicographical order
      // of its members

      // but here's the impls if we wrote them out by hand
      impl Ord for Point {
      fn cmp(&self, other: &Self) -> Ordering {
      match self.x.cmp(&other.x) {
      Ordering::Equal => self.y.cmp(&other.y),
      ordering => ordering,
      }
      }
      }
      impl PartialOrd for Point {
      fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
      Some(self.cmp(other))
      }
      }
      impl PartialEq for Point {
      fn eq(&self, other: &Self) -> bool {
      self.cmp(other) == Ordering::Equal
      }
      }
      impl Eq for Point {}
  4. 特点

    1. 表示集合论的全序

      https://zh.wikipedia.org/wiki/全序关系

      集合中上的一个关系,这个关系对于集合中的所有元素均具有反对称性+传递性,那么这个关系在这个集合上就是全序(Order,全序)的

      1. a < b implies !(a > b) (asymmetry) 反对称性
      2. a < b && b < c implies a < c (transitivity) 传递性
    2. Float 类型仅实现了PartialOrder Trait,但没有实现Order Trait

      因为NaN < 0 == false and NaN >= 0 == false 这两个断言都是正确的,违反了对所有元素的“反对称性”

5. Arithmetic Traits

Trait(s) Category Operator(s) Description
Add arithmetic + addition
AddAssign arithmetic += addition assignment
BitAnd arithmetic & bitwise AND
BitAndAssign arithmetic &= bitwise assignment
BitXor arithmetic ^ bitwise XOR
BitXorAssign arithmetic ^= bitwise XOR assignment
Div arithmetic / division
DivAssign arithmetic /= division assignment
Mul arithmetic * multiplication
MulAssign arithmetic *= multiplication assignment
Neg arithmetic - unary negation
Not arithmetic ! unary logical negation
Rem arithmetic % remainder
RemAssign arithmetic %= remainder assignment
Shl arithmetic << left shift
ShlAssign arithmetic <<= left shift assignment
Shr arithmetic >> right shift
ShrAssign arithmetic >>= right shift assignment
Sub arithmetic - subtraction
SubAssign arithmetic -= subtraction assignment

6. Closure Traits

Trait(s) Category Operator(s) Description
Fn closure (…args) immutable closure invocation
FnMut closure (…args) mutable closure invocation
FnOnce closure (…args) one-time closure invocation

包含三个Trait:Fn/FnMut/FnOnce

  1. 定义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    trait FnOnce<Args> {
    type Output;
    fn call_once(self, args: Args) -> Self::Output;
    }

    trait FnMut<Args>: FnOnce<Args> {
    fn call_mut(&mut self, args: Args) -> Self::Output;
    }

    trait Fn<Args>: FnMut<Args> {
    fn call(&self, args: Args) -> Self::Output;
    }
  2. 实现

    虽然存在这些 trait,但是在 stable 的 Rust 中,我们无法为自己的类型实现这些 trait。我们能够创建的唯一能够实现这些 trait 的类型就是闭包。闭包根据其从环境中所捕获的内容来决定它到底是实现FnOnce、FnMut还是Fn。

  3. 特点

    1. FnOnce只能被调用一次

      执行这个闭包的时候会“移动”一些值

      1
      2
      3
      4
      5
      6
      fn main() {
      let range = 0..10;
      let get_range_count = || range.count();
      assert_eq!(get_range_count(), 10); // ✅
      get_range_count(); // ❌
      }
    2. FnMut

      1. FnMut闭包可以被多次调用,并且可以修改它从环境中捕获到的变量。FnMut闭包是“有状态的”

        这是一个例子,闭包会修改外部的min,并将nums中所有不是升序的值删掉

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        fn main() {
        let nums = vec![0, 4, 2, 8, 10, 7, 15, 18, 13];
        let mut min = i32::MIN;
        let ascending = nums.into_iter().filter(|&n| {
        if n <= min {
        false
        } else {
        min = n;
        true
        }
        }).collect::<Vec<_>>();
        assert_eq!(vec![0, 4, 8, 10, 15, 18], ascending); // ✅
        }
      2. FnMut是FnOnce的子集,

        • FnOnce会获取它的参数的所有权并且只能被调用一次,
        • FnMut仅要求获取参数的可变引用并且可以被多次调用,
        • FnMut细化了FnOnce。FnMut可以被用于任何可以使用FnOnce的地方。
    3. Fn

      1. Fn闭包也可以被调用多次,但是不能修改外部环境的变量,但可以访问。Fn是“无状态”的

        1
        2
        3
        4
        5
        6
        fn main() {
        let nums = vec![0, 4, 2, 8, 10, 7, 15, 18, 13];
        let min = 9;
        let greater_than_9 = nums.into_iter().filter(|&n| n > min).collect::<Vec<_>>();
        assert_eq!(vec![10, 15, 18, 13], greater_than_9); // ✅
        }
      2. Fn是FnMut的子集

        • FnMut要求可变引用并且可以被多次调用,
        • Fn只要求不可变引用并可以被多次调用,
        • Fn细化了FnMut。Fn可以被用于任何可以使用FnMut的地方,当然也包括可以使用FnOnce的地方。
  4. 其他

    1. 如果一个闭包不访问任何环境中的变量,从技术角度来讲它算不上是闭包,而只是一个被匿名声明的内联函数,并且可以作为一个普通函数指针(即Fn)被使用和传递,这包括可以使用FnMut和FnOnce的地方。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      fn add_one(x: i32) -> i32 {
      x + 1
      }

      fn main() {
      let mut fn_ptr: fn(i32) -> i32 = add_one;
      assert_eq!(fn_ptr(1), 2); // ✅

      // capture-less closure cast to fn pointer
      fn_ptr = |x| x + 1; // same as add_one
      assert_eq!(fn_ptr(1), 2); // ✅
      }
      下面是一个传递普通函数指针而不是闭包的示例:
      1
      2
      3
      4
      5
      fn main() {
      let nums = vec![-1, 1, -2, 2, -3, 3];
      let absolutes: Vec<i32> = nums.into_iter().map(i32::abs).collect();
      assert_eq!(vec![1, 1, 2, 2, 3, 3], absolutes); // ✅
      }

7. Deref Trait

Trait(s) Category Operator(s) Description
Deref other * immutable dereference 不可变引用
DerefMut other * mutable derenence 可变引用
  1. 定义

    1
    2
    3
    4
    5
    6
    7
    8
    trait Deref {
    type Target: ?Sized;
    fn deref(&self) -> &Self::Target;
    }

    trait DerefMut: Deref {
    fn deref_mut(&mut self) -> &mut Self::Target;
    }
  2. 功能

    Deref<Target = T>类型可以使用 * 操作符解引用为T类型。

  3. 特点

    1. 当类型被作为函数参数传递、从函数返回或者作为方法调用的一部分时,Rust 会自动对这些类型进行解引用。
      1. 我们可以在一个期望&str&[T]的函数中可以传入&String&Vec<T>
        1. String实现了Deref<Target = str>
        2. Vec<T>实现了Deref<Target = [T]>
    2. Deref和DerefMut应该仅被实现于智能指针类型。
    3. 不要用deref来实现OOP的多态

8. Index & IndexMut

  1. 定义

    1
    2
    3
    4
    5
    6
    7
    8
    trait Index<Idx: ?Sized> {
    type Output: ?Sized;
    fn index(&self, index: Idx) -> &Self::Output;
    }

    trait IndexMut<Idx>: Index<Idx> where Idx: ?Sized {
    fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
    }
  2. 功能

    1. 我们可以用[]索引具有 T 值的Index<T, Output = U>类型,索引操作将返回&U值。
  3. 特点

    1. 索引操作后,编译器默认在返回值前插入解引用

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      fn main() {
      // Vec<i32> impls Index<usize, Output = i32> so
      // indexing Vec<i32> should produce &i32s and yet...
      let vec = vec![1, 2, 3, 4, 5];
      let num_ref: &i32 = vec[0]; // ❌ expected &i32 found i32

      // above line actually desugars to
      let num_ref: &i32 = *vec[0]; // ❌ expected &i32 found i32

      // both of these alternatives work
      let num: i32 = vec[0]; // ✅
      let num_ref = &vec[0]; // ✅
      }
    2. 用来索引的Idx是一个泛型,举几个其他类型用来索引的例子

      1. 可以是usize

      2. 可以是其他整数类型

        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
        46
        47
        48
        49
        50
        51
        use std::ops::Index;

        struct WrappingIndex<T>(Vec<T>);

        impl<T> Index<usize> for WrappingIndex<T> {
        type Output = T;
        fn index(&self, index: usize) -> &T {
        &self.0[index % self.0.len()]
        }
        }

        impl<T> Index<i128> for WrappingIndex<T> {
        type Output = T;
        fn index(&self, index: i128) -> &T {
        let self_len = self.0.len() as i128;
        let idx = (((index % self_len) + self_len) % self_len) as usize;
        &self.0[idx]
        }
        }

        #[test] // ✅
        fn indexes() {
        let wrapping_vec = WrappingIndex(vec![1, 2, 3]);
        assert_eq!(1, wrapping_vec[0_usize]);
        assert_eq!(2, wrapping_vec[1_usize]);
        assert_eq!(3, wrapping_vec[2_usize]);
        }

        #[test] // ✅
        fn wrapping_indexes() {
        let wrapping_vec = WrappingIndex(vec![1, 2, 3]);
        assert_eq!(1, wrapping_vec[3_usize]);
        assert_eq!(2, wrapping_vec[4_usize]);
        assert_eq!(3, wrapping_vec[5_usize]);
        }

        #[test] // ✅
        fn neg_indexes() {
        let wrapping_vec = WrappingIndex(vec![1, 2, 3]);
        assert_eq!(1, wrapping_vec[-3_i128]);
        assert_eq!(2, wrapping_vec[-2_i128]);
        assert_eq!(3, wrapping_vec[-1_i128]);
        }

        #[test] // ✅
        fn wrapping_neg_indexes() {
        let wrapping_vec = WrappingIndex(vec![1, 2, 3]);
        assert_eq!(1, wrapping_vec[-6_i128]);
        assert_eq!(2, wrapping_vec[-5_i128]);
        assert_eq!(3, wrapping_vec[-4_i128]);
        }
      3. 可以是满足 Range 的类型

        下面这个例子中,1.. /..4/1..4 都是满足 Range 的类型

        1
        2
        3
        4
        5
        6
        7
        fn main() {
        let vec = vec![1, 2, 3, 4, 5];
        assert_eq!(&vec[..], &[1, 2, 3, 4, 5]); // ✅
        assert_eq!(&vec[1..], &[2, 3, 4, 5]); // ✅
        assert_eq!(&vec[..4], &[1, 2, 3, 4]); // ✅
        assert_eq!(&vec[1..4], &[2, 3, 4]); // ✅
        }
      4. 可以是枚举

        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
        use std::ops::Index;

        enum BasketballPosition {
        PointGuard,
        ShootingGuard,
        Center,
        PowerForward,
        SmallForward,
        }

        struct BasketballPlayer {
        name: &'static str,
        position: BasketballPosition,
        }

        struct BasketballTeam {
        point_guard: BasketballPlayer,
        shooting_guard: BasketballPlayer,
        center: BasketballPlayer,
        power_forward: BasketballPlayer,
        small_forward: BasketballPlayer,
        }

        impl Index<BasketballPosition> for BasketballTeam {
        type Output = BasketballPlayer;
        fn index(&self, position: BasketballPosition) -> &BasketballPlayer {
        match position {
        BasketballPosition::PointGuard => &self.point_guard,
        BasketballPosition::ShootingGuard => &self.shooting_guard,
        BasketballPosition::Center => &self.center,
        BasketballPosition::PowerForward => &self.power_forward,
        BasketballPosition::SmallForward => &self.small_forward,
        }
        }
        }

8. Drop Trait

  1. 定义

    1
    2
    3
    trait Drop {
    fn drop(&mut self);
    }
  2. 作用

    drop函数会在该类型离开作用域但是销毁之前被调用。用来销毁某些外部资源

  3. 例子

    1. 标准库中有一个BufWriter类型让我们能够把写入的数据缓冲到Write类型中。

      为了避免Bufwriter的内容在写入底层write类型之前就被销毁,Bufwirter实现了Drop Trait

      让Bufwriter对象在销毁前保证刷新缓冲区

      1
      2
      3
      4
      5
      impl<W: Write> Drop for BufWriter<W> {
      fn drop(&mut self) {
      self.flush_buf();
      }
      }
    2. Rust 中的Mutexs没有unlock()方法,因为它们不需要!

      1. 在Mutex上调用lock()会返回一个MutexGuard,
      2. 当MutexGuard离开作用域时,它会调用drop函数自动解锁(unlock)Mutex,
      1
      2
      3
      4
      5
      6
      7
      impl<T: ?Sized> Drop for MutexGuard<'_, T> {
      fn drop(&mut self) {
      unsafe {
      self.lock.inner.raw_unlock();
      }
      }
      }

六、Conversion Traits

1. From&Into

  1. 定义

    1
    2
    3
    trait From<T> {
    fn from(T) -> Self;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    trait Into<T> {
    fn into(self) -> T;
    }

    impl<T, U> Into<U> for T
    where
    U: From<T>,
    {
    fn into(self) -> U {
    U::from(self)
    }
    }
  2. 作用

    1. From Trait允许把T类型转换为Self类型(通常为自己实现的类型)
    2. 只能为自己的类型实现From,因为Into的实现会通过 generic blanket impl 自动提供
  3. 使用例子

    1. 基础例子

      1. 可以从(x,y)tuple或者 array 转换为Point类型

        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
        46
        struct Point {
        x: i32,
        y: i32,
        }

        impl From<(i32, i32)> for Point {
        fn from((x, y): (i32, i32)) -> Self {
        Point { x, y }
        }
        }

        impl From<Point> for (i32, i32) {
        fn from(Point { x, y }: Point) -> Self {
        (x, y)
        }
        }

        impl From<[i32; 2]> for Point {
        fn from([x, y]: [i32; 2]) -> Self {
        Point { x, y }
        }
        }

        impl From<Point> for [i32; 2] {
        fn from(Point { x, y }: Point) -> Self {
        [x, y]
        }
        }

        fn example() {
        // 从 (i32, i32) 到 Point
        let point = Point::from((0, 0));
        let point: Point = (0, 0).into();

        // 从 Point 到 (i32, i32)
        let tuple = <(i32, i32)>::from(point);
        let tuple: (i32, i32) = point.into();

        // 从 [i32; 2] 到 Point
        let point = Point::from([0, 0]);
        let point: Point = [0, 0].into();

        // 从 Point 到 [i32; 2]
        let array = <[i32; 2]>::from(point);
        let array: [i32; 2] = point.into();
        }
    2. 使得“需要对参数拥有所有权的”函数具有通用型,不关心传进来的参数是拥有值还是值得引用

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      struct Person {
      name: String,
      }

      impl Person {
      // 接受:
      // - String
      fn new1(name: String) -> Person {
      Person { name }
      }

      // 接受:
      // - String
      // - &String
      // - &str
      // - Box<str>
      // - Cow<'_, str>
      // - char
      // 因为上面所有的类型都可以转换为 String
      fn new2<N: Into<String>>(name: N) -> Person {
      Person { name: name.into() }
      }
      }

七、错误处理

1. Error Trait

  1. 定义

    1
    2
    3
    4
    5
    6
    7
    trait Error: Debug + Display {
    // 提供默认实现
    fn source(&self) -> Option<&(dyn Error + 'static)>;
    fn backtrace(&self) -> Option<&Backtrace>;
    fn description(&self) -> &str;
    fn cause(&self) -> Option<&dyn Error>;
    }
  2. 功能

    1. rust中,错误是被return返回的,而不是被throw抛出的
  3. 一个例子

    1. 安全除法

      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
      use std::fmt;
      use std::error;

      #[derive(Debug, PartialEq)]
      struct DivByZero;

      impl fmt::Display for DivByZero {
      fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
      write!(f, "division by zero error")
      }
      }

      impl error::Error for DivByZero {}

      fn safe_div(numerator: i32, denominator: i32) -> Result<i32, DivByZero> {
      if denominator == 0 {
      return Err(DivByZero);
      }
      Ok(numerator / denominator)
      }

      #[test] // ✅
      fn test_safe_div() {
      assert_eq!(safe_div(8, 2), Ok(4));
      assert_eq!(safe_div(5, 0), Err(DivByZero));
      }
  4. 特点

    1. 错误是被返回而不是被抛出,所以这些错误必须被显式地处理,如果当前函数无法处理错误,该函数应该把错误传递给自己的调用者。

    2. 传递错误的最常用方式是使用?操作符,它是现在已经弃用的try!宏的语法糖

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      macro_rules! try {
      ($expr:expr) => {
      match $expr {
      // if Ok just unwrap the value
      Ok(val) => val,
      // if Err map the err value using From and return
      Err(err) => {
      return Err(From::from(err));
      }
      }
      };
      }
    3. 一个返回io::Error的例子

      1. 这个例子中,所有可能的error都是io::Error类型的

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        use std::io::Read;
        use std::path::Path;
        use std::io;
        use std::fs::File;

        fn read_file_to_string(path: &Path) -> Result<String, io::Error> {
        let mut file = File::open(path)?; // ⬆️ io::Error
        let mut contents = String::new();
        file.read_to_string(&mut contents)?; // ⬆️ io::Error
        Ok(contents)
        }
    4. 如何返回不同种类的Error

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      use std::io::Read;
      use std::path::Path;
      use std::io;
      use std::fs::File;

      fn sum_file(path: &Path) -> Result<i32, /*这里放置什么? */> {
      let mut file = File::open(path)?; // ⬆️ io::Error
      let mut contents = String::new();
      file.read_to_string(&mut contents)?; // ⬆️ io::Error
      let mut sum = 0;
      for line in contents.lines() {
      sum += line.parse::<i32>()?; // ⬆️ ParseIntError
      }
      Ok(sum)
      }
      1. 一种方法是,使用dyn error::Error 接受任意类型Error

        1. 任何一种error类型均可以转换为Box 类型

          1
          impl<E: error::Error> From<E> for Box<dyn error::Error>;
        2. 所以,任意一种Error均可以通过Box 返回给调用者

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          use std::fs::File;
          use std::io::Read;
          use std::path::Path;
          use std::error;

          fn sum_file(path: &Path) -> Result<i32, Box<dyn error::Error>> {
          let mut file = File::open(path)?; // ⬆️ io::Error -> Box<dyn error::Error>
          let mut contents = String::new();
          file.read_to_string(&mut contents)?; // ⬆️ io::Error -> Box<dyn error::Error>
          let mut sum = 0;
          for line in contents.lines() {
          sum += line.parse::<i32>()?; // ⬆️ ParseIntError -> Box<dyn error::Error>
          }
          Ok(sum)
          }
        3. 如果调用者想知道返回错误的具体类型,需要使用downcast_ref()

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          fn handle_sum_file_errors(path: &Path) {
          match sum_file(path) {
          Ok(sum) => println!("the sum is {}", sum),
          Err(err) => {
          if let Some(e) = err.downcast_ref::<io::Error>() {
          // 处理 io::Error
          } else if let Some(e) = err.downcast_ref::<ParseIntError>() {
          // 处理 ParseIntError
          } else {
          // 我们知道 sum_file 只会返回上面错误中的其中一个
          // 所以不会到达这个分支
          unreachable!();
          }
          }
          }
          }
      2. 第二种方法是:使用Enum类型枚举所有可能的error

        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
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        use std::num::ParseIntError;
        use std::fs::File;
        use std::io;
        use std::io::Read;
        use std::path::Path;
        use std::error;
        use std::fmt;

        #[derive(Debug)]
        enum SumFileError {
        Io(io::Error),
        Parse(ParseIntError),
        }

        impl From<io::Error> for SumFileError {
        fn from(err: io::Error) -> Self {
        SumFileError::Io(err)
        }
        }

        impl From<ParseIntError> for SumFileError {
        fn from(err: ParseIntError) -> Self {
        SumFileError::Parse(err)
        }
        }

        impl fmt::Display for SumFileError {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
        SumFileError::Io(err) => write!(f, "sum file error: {}", err),
        SumFileError::Parse(err) => write!(f, "sum file error: {}", err),
        }
        }
        }

        impl error::Error for SumFileError {
        // 这个方法的默认实现总是返回 None
        //但是我们现在重写它,让它更有用
        fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        Some(match self {
        SumFileError::Io(err) => err,
        SumFileError::Parse(err) => err,
        })
        }
        }

        fn sum_file(path: &Path) -> Result<i32, SumFileError> {
        let mut file = File::open(path)?; // ⬆️ io::Error -> SumFileError
        let mut contents = String::new();
        file.read_to_string(&mut contents)?; // ⬆️ io::Error -> SumFileError
        let mut sum = 0;
        for line in contents.lines() {
        sum += line.parse::<i32>()?; // ⬆️ ParseIntError -> SumFileError
        }
        Ok(sum)
        }

        fn handle_sum_file_errors(path: &Path) {
        match sum_file(path) {
        Ok(sum) => println!("the sum is {}", sum),
        Err(SumFileError::Io(err)) => {
        // 处理 io::Error
        },
        Err(SumFileError::Parse(err)) => {
        // 处理 ParseIntError
        },
        }
        }

六、转换类型(续)

1. TryFrom & TryInto

  1. 定义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    trait TryFrom<T> {
    type Error;
    fn try_from(value: T) -> Result<Self, Self::Error>;
    }

    trait TryInto<T> {
    type Error;
    fn try_into(self) -> Result<T, Self::Error>;
    }
  2. 功能:允许失败版本的From/Into

  3. 一个例子

    1. Point中的x和y如果值小于-1000或者大于1000没有意义,则可以如下实现转换函数

      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
      use std::convert::TryFrom;
      use std::error;
      use std::fmt;

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

      #[derive(Debug)]
      struct OutOfBounds;

      impl fmt::Display for OutOfBounds {
      fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
      write!(f, "out of bounds")
      }
      }

      impl error::Error for OutOfBounds {}

      // 现在是可以出错的
      impl TryFrom<(i32, i32)> for Point {
      type Error = OutOfBounds;
      fn try_from((x, y): (i32, i32)) -> Result<Point, OutOfBounds> {
      if x.abs() > 1000 || y.abs() > 1000 {
      return Err(OutOfBounds);
      }
      Ok(Point { x, y })
      }
      }

      // 仍然是不会出错的
      impl From<Point> for (i32, i32) {
      fn from(Point { x, y }: Point) -> Self {
      (x, y)
      }
      }

2. FromStr

  1. 定义

    1
    2
    3
    4
    trait FromStr {
    type Err;
    fn from_str(s: &str) -> Result<Self, Self::Err>;
    }
  2. 功能

    FromStr 类型允许执行一个从&str到Self的可失败的转换。最常见的使用是在&str上调用.parse()方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    use std::str::FromStr;

    fn example<T: FromStr>(s: &'static str) {
    // 这些都是相等的
    let t: Result<T, _> = FromStr::from_str(s);
    let t = T::from_str(s);
    let t: Result<T, _> = s.parse();
    let t = s.parse::<T>(); // 最常见的
    }
  3. 一个例子

    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    use std::error;
    use std::fmt;
    use std::iter::Enumerate;
    use std::num::ParseIntError;
    use std::str::{Chars, FromStr};

    #[derive(Debug, Eq, PartialEq)]
    struct Point {
    x: i32,
    y: i32,
    }

    impl Point {
    fn new(x: i32, y: i32) -> Self {
    Point { x, y }
    }
    }

    #[derive(Debug, PartialEq)]
    struct ParsePointError;

    impl fmt::Display for ParsePointError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    write!(f, "failed to parse point")
    }
    }

    impl From<ParseIntError> for ParsePointError {
    fn from(_e: ParseIntError) -> Self {
    ParsePointError
    }
    }

    impl error::Error for ParsePointError {}

    impl FromStr for Point {
    type Err = ParsePointError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
    let is_num = |(_, c): &(usize, char)| matches!(c, '0'..='9' | '-');
    let isnt_num = |t: &(_, _)| !is_num(t);

    let get_num =
    |char_idxs: &mut Enumerate<Chars<'_>>| -> Result<(usize, usize), ParsePointError> {
    let (start, _) = char_idxs
    .skip_while(isnt_num)
    .next()
    .ok_or(ParsePointError)?;
    let (end, _) = char_idxs
    .skip_while(is_num)
    .next()
    .ok_or(ParsePointError)?;
    Ok((start, end))
    };

    let mut char_idxs = s.chars().enumerate();
    let (x_start, x_end) = get_num(&mut char_idxs)?;
    let (y_start, y_end) = get_num(&mut char_idxs)?;

    let x = s[x_start..x_end].parse::<i32>()?;
    let y = s[y_start..y_end].parse::<i32>()?;

    Ok(Point { x, y })
    }
    }

    #[test] // ✅
    fn pos_x_y() {
    let p = "(4, 5)".parse::<Point>();
    assert_eq!(p, Ok(Point::new(4, 5)));
    }

    #[test] // ✅
    fn neg_x_y() {
    let p = "(-6, -2)".parse::<Point>();
    assert_eq!(p, Ok(Point::new(-6, -2)));
    }

    #[test] // ✅
    fn not_a_point() {
    let p = "not a point".parse::<Point>();
    assert_eq!(p, Err(ParsePointError));
    }
  4. 特点

    1. FromStr和TryFrom<&str>有着相同的签名。只要我们通过其中一个实现另一个,先实现哪个并不重要。

      1. 一个例子
      1
      2
      3
      4
      5
      6
      impl TryFrom<&str> for Point {
      type Error = <Point as FromStr>::Err;
      fn try_from(s: &str) -> Result<Point, Self::Error> {
      <Point as FromStr>::from_str(s)
      }
      }

2. AsRef & AsMut

  1. 定义

    1
    2
    3
    4
    5
    6
    7
    trait AsRef<T: ?Sized> {
    fn as_ref(&self) -> &T;
    }

    trait AsMut<T: ?Sized> {
    fn as_mut(&mut self) -> &mut T;
    }
  2. 作用:

    1. 总的来说,AsRef被用于轻量级的引用到引用之间的转换。下面举几个实际的例子

    2. AsRef trait可以使函数在是否获取所有权上具有通用性:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      // accepts:
      // - &str
      // - &String
      fn takes_str(s: &str) {
      // use &str
      }

      // accepts:
      // - &str
      // - &String
      // - String
      fn takes_asref_str<S: AsRef<str>>(s: S) {
      let s: &str = s.as_ref();
      // use &str
      }

      fn example(slice: &str, borrow: &String, owned: String) {
      takes_str(slice);
      takes_str(borrow);
      takes_str(owned); // ❌
      takes_asref_str(slice);
      takes_asref_str(borrow);
      takes_asref_str(owned); // ✅
      }
    3. AsRef 可以返回类型内部私有数据的引用。通常这个私有数据被一个不可变类型所包裹

      例如标准库的String, 包裹了Vec 作为私有数据。内部的Vec不能被公开,因为如果这样的话,人们就会修改里面的字节并破坏String中有效的 UTF-8 编码。但是,暴露内部字节数组的一个不可变的只读引用是安全的,

      1
      2
      3
      4
      struct String {
      vec: Vec<u8>,
      }
      impl AsRef<[u8]> for String;
    4. AsRef用于语义相等的事物之间引用到引用的转换,

      1. 一个反例

        下面是为任意类型实现AsRef

        User 包含String/u32, 但User不是String/u32。对于这样的类型实现AsRef没有什么意义,

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        struct User {
        name: String,
        email: String,
        age: u32,
        height: u32,
        }

        impl AsRef<String> for User {
        fn as_ref(&self) -> &String {、
        //我们返回 name 还是 email?
        }
        }

        impl AsRef<u32> for User {
        fn as_ref(&self) -> &u32 {
        //我们返回 age 还是 height?
        }
        }
      2. 一个正确的例子

        Moderator 是一个User,User可以做的事情,Moderator也应该可以做

        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
        46
        47
        struct User {
        name: String,
        age: u32,
        }

        //不幸地是,标准库并没有提供一个generic blanket impl来避免这种重复的实现
        impl AsRef<User> for User {
        fn as_ref(&self) -> &User {
        self
        }
        }

        enum Privilege {
        BanUsers,
        EditPosts,
        DeletePosts,
        }

        //尽管 Moderators 有一些特殊权限,它们仍然是普通的 User
        //并且应该做相同的事情
        struct Moderator {
        user: User,
        privileges: Vec<Privilege>
        }

        impl AsRef<Moderator> for Moderator {
        fn as_ref(&self) -> &Moderator {
        self
        }
        }

        impl AsRef<User> for Moderator {
        fn as_ref(&self) -> &User {
        &self.user
        }
        }

        //使用 User 和 Moderators (也是一种User)应该都是可以调用的
        fn create_post<U: AsRef<User>>(u: U) {
        let user = u.as_ref();
        // etc
        }

        fn example(user: User, moderator: Moderator) {
        create_post(&user);
        create_post(&moderator); // ✅
        }

3. Borrow/BorrowMut

  1. 定义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    trait Borrow<Borrowed>
    where
    Borrowed: ?Sized,
    {
    fn borrow(&self) -> &Borrowed;
    }

    trait BorrowMut<Borrowed>: Borrow<Borrowed>
    where
    Borrowed: ?Sized,
    {
    fn borrow_mut(&mut self) -> &mut Borrowed;
    }
  2. 作用

    1. 最初的作用:使用&str类型的值在HashSet、HashMap、BTreeSet和BTreeMap中查找String类型的 key。
    2. 我们可以把Borrow和BorrowMut看作更严格的AsRef和AsMut,它们返回的引用&T与Self有等价性的Eq、Hash和Ord实现。
  3. 例子

    borrow/borrow_mut 返回的引用 是满足Eq、Hash、Ord三个Trait的

    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    use std::borrow::Borrow;
    use std::hash::Hasher;
    use std::collections::hash_map::DefaultHasher;
    use std::hash::Hash;

    fn get_hash<T: Hash>(t: T) -> u64 {
    let mut hasher = DefaultHasher::new();
    t.hash(&mut hasher);
    hasher.finish()
    }

    fn asref_example<Owned, Ref>(owned1: Owned, owned2: Owned)
    where
    Owned: Eq + Ord + Hash + AsRef<Ref>,
    Ref: Eq + Ord + Hash
    {
    let ref1: &Ref = owned1.as_ref();
    let ref2: &Ref = owned2.as_ref();

    // refs aren't required to be equal if owned types are equal
    assert_eq!(owned1 == owned2, ref1 == ref2); // ❌

    let owned1_hash = get_hash(&owned1);
    let owned2_hash = get_hash(&owned2);
    let ref1_hash = get_hash(&ref1);
    let ref2_hash = get_hash(&ref2);

    // ref hashes aren't required to be equal if owned type hashes are equal
    assert_eq!(owned1_hash == owned2_hash, ref1_hash == ref2_hash); // ❌

    // ref comparisons aren't required to match owned type comparisons
    assert_eq!(owned1.cmp(&owned2), ref1.cmp(&ref2)); // ❌
    }

    fn borrow_example<Owned, Borrowed>(owned1: Owned, owned2: Owned)
    where
    Owned: Eq + Ord + Hash + Borrow<Borrowed>,
    Borrowed: Eq + Ord + Hash
    {
    let borrow1: &Borrowed = owned1.borrow();
    let borrow2: &Borrowed = owned2.borrow();

    // borrows are required to be equal if owned types are equal
    assert_eq!(owned1 == owned2, borrow1 == borrow2); // ✅

    let owned1_hash = get_hash(&owned1);
    let owned2_hash = get_hash(&owned2);
    let borrow1_hash = get_hash(&borrow1);
    let borrow2_hash = get_hash(&borrow2);

    // borrow hashes are required to be equal if owned type hashes are equal
    assert_eq!(owned1_hash == owned2_hash, borrow1_hash == borrow2_hash); // ✅

    // borrow comparisons are required to match owned type comparisons
    assert_eq!(owned1.cmp(&owned2), borrow1.cmp(&borrow2)); // ✅
    }
  4. 特点

    1. 这个Trait是为一个类型的引用类型准备的,很少由程序员手动实现引用类型的Trait
    2. T:Borrorw<T>已经为所有的类型T实现了,所以我们不需要手动地实现它;并且我们不需要创建一个U以用来T:Borrow<U>

4. ToOwned

  1. 定义

    1
    2
    3
    4
    5
    6
    7
    trait ToOwned {
    type Owned: Borrow<Self>;
    fn to_owned(&self) -> Self::Owned;

    // 提供默认实现
    fn clone_into(&self, target: &mut Self::Owned);
    }
  2. 作用

    1. ToOwned是Clone的一个更为通用的版本。Clone允许我们获取一个&T并把它转为一个T,但是ToOwned允许我们拿到一个&Borrowed并把它转为一个Owned,其中Owned: Borrow
      1. 换句话说,我们不能从一个&str克隆一个String,或者从一个&Path克隆一个PathBuf,或者从一个&OsStr克隆一个OsString,因为clone方法签名不支持这种跨类型的克隆,这就是ToOwned产生的原因。

八、Iteration Traits

1. Iterator

  1. 定义

    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;

    // provided default impls
    fn size_hint(&self) -> (usize, Option<usize>);
    fn count(self) -> usize;
    fn last(self) -> Option<Self::Item>;
    fn advance_by(&mut self, n: usize) -> Result<(), usize>;
    fn nth(&mut self, n: usize) -> Option<Self::Item>;
    fn step_by(self, step: usize) -> StepBy<Self>;
    fn chain<U>(
    self,
    other: U
    ) -> Chain<Self, <U as IntoIterator>::IntoIter>
    where
    U: IntoIterator<Item = Self::Item>;
    fn zip<U>(self, other: U) -> Zip<Self, <U as IntoIterator>::IntoIter>
    where
    U: IntoIterator;
    fn map<B, F>(self, f: F) -> Map<Self, F>
    where
    F: FnMut(Self::Item) -> B;
    fn for_each<F>(self, f: F)
    where
    F: FnMut(Self::Item);
    fn filter<P>(self, predicate: P) -> Filter<Self, P>
    where
    P: FnMut(&Self::Item) -> bool;
    fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>
    where
    F: FnMut(Self::Item) -> Option<B>;
    fn enumerate(self) -> Enumerate<Self>;
    fn peekable(self) -> Peekable<Self>;
    fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>
    where
    P: FnMut(&Self::Item) -> bool;
    fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
    where
    P: FnMut(&Self::Item) -> bool;
    fn map_while<B, P>(self, predicate: P) -> MapWhile<Self, P>
    where
    P: FnMut(Self::Item) -> Option<B>;
    fn skip(self, n: usize) -> Skip<Self>;
    fn take(self, n: usize) -> Take<Self>;
    fn scan<St, B, F>(self, initial_state: St, f: F) -> Scan<Self, St, F>
    where
    F: FnMut(&mut St, Self::Item) -> Option<B>;
    fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
    where
    F: FnMut(Self::Item) -> U,
    U: IntoIterator;
    fn flatten(self) -> Flatten<Self>
    where
    Self::Item: IntoIterator;
    fn fuse(self) -> Fuse<Self>;
    fn inspect<F>(self, f: F) -> Inspect<Self, F>
    where
    F: FnMut(&Self::Item);
    fn by_ref(&mut self) -> &mut Self;
    fn collect<B>(self) -> B
    where
    B: FromIterator<Self::Item>;
    fn partition<B, F>(self, f: F) -> (B, B)
    where
    F: FnMut(&Self::Item) -> bool,
    B: Default + Extend<Self::Item>;
    fn partition_in_place<'a, T, P>(self, predicate: P) -> usize
    where
    Self: DoubleEndedIterator<Item = &'a mut T>,
    T: 'a,
    P: FnMut(&T) -> bool;
    fn is_partitioned<P>(self, predicate: P) -> bool
    where
    P: FnMut(Self::Item) -> bool;
    fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
    where
    F: FnMut(B, Self::Item) -> R,
    R: Try<Ok = B>;
    fn try_for_each<F, R>(&mut self, f: F) -> R
    where
    F: FnMut(Self::Item) -> R,
    R: Try<Ok = ()>;
    fn fold<B, F>(self, init: B, f: F) -> B
    where
    F: FnMut(B, Self::Item) -> B;
    fn fold_first<F>(self, f: F) -> Option<Self::Item>
    where
    F: FnMut(Self::Item, Self::Item) -> Self::Item;
    fn all<F>(&mut self, f: F) -> bool
    where
    F: FnMut(Self::Item) -> bool;
    fn any<F>(&mut self, f: F) -> bool
    where
    F: FnMut(Self::Item) -> bool;
    fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
    where
    P: FnMut(&Self::Item) -> bool;
    fn find_map<B, F>(&mut self, f: F) -> Option<B>
    where
    F: FnMut(Self::Item) -> Option<B>;
    fn try_find<F, R>(
    &mut self,
    f: F
    ) -> Result<Option<Self::Item>, <R as Try>::Error>
    where
    F: FnMut(&Self::Item) -> R,
    R: Try<Ok = bool>;
    fn position<P>(&mut self, predicate: P) -> Option<usize>
    where
    P: FnMut(Self::Item) -> bool;
    fn rposition<P>(&mut self, predicate: P) -> Option<usize>
    where
    Self: ExactSizeIterator + DoubleEndedIterator,
    P: FnMut(Self::Item) -> bool;
    fn max(self) -> Option<Self::Item>
    where
    Self::Item: Ord;
    fn min(self) -> Option<Self::Item>
    where
    Self::Item: Ord;
    fn max_by_key<B, F>(self, f: F) -> Option<Self::Item>
    where
    F: FnMut(&Self::Item) -> B,
    B: Ord;
    fn max_by<F>(self, compare: F) -> Option<Self::Item>
    where
    F: FnMut(&Self::Item, &Self::Item) -> Ordering;
    fn min_by_key<B, F>(self, f: F) -> Option<Self::Item>
    where
    F: FnMut(&Self::Item) -> B,
    B: Ord;
    fn min_by<F>(self, compare: F) -> Option<Self::Item>
    where
    F: FnMut(&Self::Item, &Self::Item) -> Ordering;
    fn rev(self) -> Rev<Self>
    where
    Self: DoubleEndedIterator;
    fn unzip<A, B, FromA, FromB>(self) -> (FromA, FromB)
    where
    Self: Iterator<Item = (A, B)>,
    FromA: Default + Extend<A>,
    FromB: Default + Extend<B>;
    fn copied<'a, T>(self) -> Copied<Self>
    where
    Self: Iterator<Item = &'a T>,
    T: 'a + Copy;
    fn cloned<'a, T>(self) -> Cloned<Self>
    where
    Self: Iterator<Item = &'a T>,
    T: 'a + Clone;
    fn cycle(self) -> Cycle<Self>
    where
    Self: Clone;
    fn sum<S>(self) -> S
    where
    S: Sum<Self::Item>;
    fn product<P>(self) -> P
    where
    P: Product<Self::Item>;
    fn cmp<I>(self, other: I) -> Ordering
    where
    I: IntoIterator<Item = Self::Item>,
    Self::Item: Ord;
    fn cmp_by<I, F>(self, other: I, cmp: F) -> Ordering
    where
    F: FnMut(Self::Item, <I as IntoIterator>::Item) -> Ordering,
    I: IntoIterator;
    fn partial_cmp<I>(self, other: I) -> Option<Ordering>
    where
    I: IntoIterator,
    Self::Item: PartialOrd<<I as IntoIterator>::Item>;
    fn partial_cmp_by<I, F>(
    self,
    other: I,
    partial_cmp: F
    ) -> Option<Ordering>
    where
    F: FnMut(Self::Item, <I as IntoIterator>::Item) -> Option<Ordering>,
    I: IntoIterator;
    fn eq<I>(self, other: I) -> bool
    where
    I: IntoIterator,
    Self::Item: PartialEq<<I as IntoIterator>::Item>;
    fn eq_by<I, F>(self, other: I, eq: F) -> bool
    where
    F: FnMut(Self::Item, <I as IntoIterator>::Item) -> bool,
    I: IntoIterator;
    fn ne<I>(self, other: I) -> bool
    where
    I: IntoIterator,
    Self::Item: PartialEq<<I as IntoIterator>::Item>;
    fn lt<I>(self, other: I) -> bool
    where
    I: IntoIterator,
    Self::Item: PartialOrd<<I as IntoIterator>::Item>;
    fn le<I>(self, other: I) -> bool
    where
    I: IntoIterator,
    Self::Item: PartialOrd<<I as IntoIterator>::Item>;
    fn gt<I>(self, other: I) -> bool
    where
    I: IntoIterator,
    Self::Item: PartialOrd<<I as IntoIterator>::Item>;
    fn ge<I>(self, other: I) -> bool
    where
    I: IntoIterator,
    Self::Item: PartialOrd<<I as IntoIterator>::Item>;
    fn is_sorted(self) -> bool
    where
    Self::Item: PartialOrd<Self::Item>;
    fn is_sorted_by<F>(self, compare: F) -> bool
    where
    F: FnMut(&Self::Item, &Self::Item) -> Option<Ordering>;
    fn is_sorted_by_key<F, K>(self, f: F) -> bool
    where
    F: FnMut(Self::Item) -> K,
    K: PartialOrd<K>;
    }
  2. 实现

    1. Iterator<Item = T>类型可以被迭代并产生T类型。没有IteratorMut trait。每个Iterator实现可以指定它返回的是不可变引用、可变引用还是拥有通过Item关联类型的值。

      Vec method Returns
      .iter() Iterator<Item = &T>
      .iter_mut() Iterator<Item = &mut T>
      .into_iter() Iterator<Item = T>
    2. 大多数类型没有它们自己的迭代器。如果一个类型是可迭代的,我们几乎总是实现自定义的迭代器类型来迭代它,而不是让它自己迭代。

      可以使用Vec 的iter方法对自己的类型迭代

      1
      2
      3
      4
      5
      6
      7
      8
      9
      struct MyType {
      items: Vec<String>
      }

      impl MyType {
      fn iter(&self) -> impl Iterator<Item = &String> {
      self.items.iter()
      }
      }
    3. It says that any mutable reference to an iterator is also an iterator. This is useful to know because it allows us to use iterator methods with self receivers as if they had &mut self receivers.

      1. 这里是说Iterator定义的方法,接受self的方法和接受&mut self的方法是一样的
    4. 如果我们想对一个超过三项的迭代器进行处理的函数,函数要先消耗三个元素,再进行处理

      1. 这是一个错误范例

        take方法接受self对象,换句话说,它消耗了iter这个实例,接下来再调用iter会报错

        1
        2
        3
        4
        5
        6
        fn example<I: Iterator<Item = i32>>(mut iter: I) {
        let first3: Vec<i32> = iter.take(3).collect();
        for item in iter { // ❌ iter consumed in line above
        // process remaining items
        }
        }
      2. 下面两种方法可以达到目的

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        fn example<I: Iterator<Item = i32>>(mut iter: I) {
        let first3: Vec<i32> = vec![
        iter.next().unwrap(),
        iter.next().unwrap(),
        iter.next().unwrap(),
        ];
        for item in iter { // ✅
        // process remaining items
        }
        }

        fn example<I: Iterator<Item = i32>>(mut iter: I) {
        let first3: Vec<i32> = iter.by_ref().take(3).collect();
        for item in iter { // ✅
        // process remaining items
        }
        }

2. IntoIter

  1. 定义

    1
    2
    3
    4
    5
    6
    7
    8
    trait IntoIterator 
    where
    <Self::IntoIter as Iterator>::Item == Self::Item,
    {
    type Item;
    type IntoIter: Iterator;
    fn into_iter(self) -> Self::IntoIter;
    }
  2. 作用

    让类型T转换为迭代器类型,对于不可变引用、可变引用也如此

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // vec = Vec<T>
    for v in vec {} // v = T

    // above line desugared
    for v in vec.into_iter() {}

    // vec = Vec<T>
    for v in &vec {} // v = &T

    // above example desugared
    for v in (&vec).into_iter() {}

    // vec = Vec<T>
    for v in &mut vec {} // v = &mut T

    // above example desugared
    for v in (&mut vec).into_iter() {}

3. FromIterator

  1. 定义

    1
    2
    3
    4
    5
    trait FromIterator<A> {
    fn from_iter<T>(iter: T) -> Self
    where
    T: IntoIterator<Item = A>;
    }
  2. 作用

    从迭代器类型转换为类型T

    比如collect方法

    1
    2
    3
    fn collect<B>(self) -> B
    where
    B: FromIterator<Self::Item>;
  3. 例子

    collect 方法“收集”一个Iterator<Item = char> 到 String:

    1
    2
    3
    fn filter_letters(string: &str) -> String {
    string.chars().filter(|c| c.is_alphabetic()).collect()
    }

4. 标准库类型靠迭代器相互转换的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use std::collections::{BTreeSet, HashMap, HashSet, LinkedList};

// String -> HashSet<char>
fn unique_chars(string: &str) -> HashSet<char> {
string.chars().collect()
}

// Vec<T> -> BTreeSet<T>
fn ordered_unique_items<T: Ord>(vec: Vec<T>) -> BTreeSet<T> {
vec.into_iter().collect()
}

// HashMap<K, V> -> LinkedList<(K, V)>
fn entry_list<K, V>(map: HashMap<K, V>) -> LinkedList<(K, V)> {
map.into_iter().collect()
}

// and countless more possible examples

九、IO Trait

1. Read/Write

  1. 定义

    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
    trait Read {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize>;

    // provided default impls
    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize>;
    fn is_read_vectored(&self) -> bool;
    unsafe fn initializer(&self) -> Initializer;
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize>;
    fn read_to_string(&mut self, buf: &mut String) -> Result<usize>;
    fn read_exact(&mut self, buf: &mut [u8]) -> Result<()>;
    fn by_ref(&mut self) -> &mut Self
    where
    Self: Sized;
    fn bytes(self) -> Bytes<Self>
    where
    Self: Sized;
    fn chain<R: Read>(self, next: R) -> Chain<Self, R>
    where
    Self: Sized;
    fn take(self, limit: u64) -> Take<Self>
    where
    Self: Sized;
    }

    trait Write {
    fn write(&mut self, buf: &[u8]) -> Result<usize>;
    fn flush(&mut self) -> Result<()>;

    // provided default impls
    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize>;
    fn is_write_vectored(&self) -> bool;
    fn write_all(&mut self, buf: &[u8]) -> Result<()>;
    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> Result<()>;
    fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result<()>;
    fn by_ref(&mut self) -> &mut Self
    where
    Self: Sized;
    }
  2. 实现

    1. 标准库同样提供了泛型覆盖实现

      Read类型的任何可变引用也都是Read,Write同理

      1
      2
      impl<R: Read + ?Sized> Read for &mut R;
      impl<W: Write + ?Sized> Write for &mut W;
  3. 例子

    &[u8] 实现了Read,Vec实现了Write

    因此我们可以对我们的文件处理函数进行简单的单元测试,通过使用String转换为&[u8]以及从Vec 转换为String:

    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
    use std::path::Path;
    use std::fs::File;
    use std::io::Read;
    use std::io::Write;
    use std::io;

    // function we want to test
    fn uppercase<R: Read, W: Write>(mut read: R, mut write: W) -> Result<(), io::Error> {
    let mut buffer = String::new();
    read.read_to_string(&mut buffer)?;
    let uppercase = buffer.to_uppercase();
    write.write_all(uppercase.as_bytes())?;
    write.flush()?;
    Ok(())
    }

    // in actual program we'd pass Files
    fn example(in_path: &Path, out_path: &Path) -> Result<(), io::Error> {
    let in_file = File::open(in_path)?;
    let out_file = File::open(out_path)?;
    uppercase(in_file, out_file)
    }

    // however in unit tests we can use Strings!
    #[test] // ✅
    fn example_test() {
    let in_file: String = "i am screaming".into();
    let mut out_file: Vec<u8> = Vec::new();
    uppercase(in_file.as_bytes(), &mut out_file).unwrap();
    let out_result = String::from_utf8(out_file).unwrap();
    assert_eq!(out_result, "I AM SCREAMING");
    }

Rust标准库涉及的Trait
https://gwzlchn.github.io/202205/rust-traits/
作者
Zelin Wang
发布于
2022年5月18日
更新于
2022年10月23日
许可协议