• 【Rust】4 一文讲解重点 pattern matching | trait | 生命周期 | 闭包 | 迭代器 | 智能指针 | 并发与并行


    本地运行 rustup doc 即可打开 rust 官方文档

    一、pattern matching

    模式匹配

        let a = 0;
        match a {
            0 => println!("zero"),
            _ => println!("non-zero"),
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    // let 就是一种 pattern match 的表达式
    #[warn(unused_variables)]
    fn main() {
        struct A {
            x: i32,
            y: &'static str,
            z: B,
        }
        #[derive(Debug)]
        enum B {
            X(i32),
            Y { a: u8, b: u8 },
            Z,
        }
        let a = A {
            x: 0,
            y: "hello",
            z: B::Y { a: 2, b: 3 },
        };
        let A { x, y, z } = a; // 模式匹配(即对 struct 的解构), xyz 都是新的变量, 将 a 赋值给他们(PS: 因为 struct A 中的属性为 xyz, 所以必须命名为 xyz)
        println!("{}, {}, {:?}", x, y, z);
    }
    
    // code result:
    0, hello, Y { a: 2, b: 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
    // if let 的 pattern matching 匹配度更高
    if let A {
        z: B::Y { a, b }, .. // ..表示忽略其他字段
    } = a
    {}
    
    if let (x, y, 3) = (10, 11, 12) {} // 若 3 != 12 则直接返回模式匹配
    
    let a = 12;
    let s = match a {
        90..=100 => "A", // ..= 会自动转换为 std::ops::RangeInclusive 结构体
        80..=89 => "B",
        70..=89 => "C",
        _ => "D",
    };
    // ..end 会自动转换为 core::ops::RangeTo, 即 x < end
    // start.. 会自动转换为 core::ops::RangeFrom, 即 x > end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    二、trait

    2.1 常见 trait

    2.1.1 Copy 和 Clone

    trait core::clone::Clone 是一个对象, 其赋值对象完整的数据(当然也包括该对象的所有权)

    所有不可变引用都实现了 Clone trait(因为不可变引用可以被持有多份, 所以可以被 Clone)

    Clone is a supertrait of Copy, so everything which is Copy must also implement Clone. If a type is Copy then its Clone implementation only needs to return *self (see the example above).

    We can derive a Copy implementation. Clone is also required, as it’s a supertrait of Copy.

    • 因为实现了 Copy 和 Clone, 所以 let b = a 并未转移所有权, 所以最后一行 a 仍可使用(仍在栈上), 如下图:

    • 而若没有实现 Copy, 则会报错, 因为 let b = a 所有权转移后, 无法再访问 a 了, 如下图:

    • 而若显式调用 .clone() 即可通过编译, 如下图:

    • 如果定义了 A.ptr 指向堆上的内存, 则只能用Clone trait 的 clone()

    • 错误用法如下: Copy trait 会造成 a.ptr 和 b.ptr 都指向同一份堆上的内存, 造成垂悬引用, 虽然 rust 编译器不会报错, 但这是不安全的, 而应当用智能指针来解决. 如下图:

    2.1.2 PartialEq 和 Eq

    Eq implies PartialEq
    区别
    PartialEq 描述的是部分相等关系(离散数学的偏序关系), 如 float 中 Nan 和 Nan 是无法比较的, 所以 float 是 PartialEq
    Eq 描述的是完全相等关系(离散数学的全序关系)

    只要实现了 PartialEq, 就可用 a == b 和 a != b 来表达

    PartialEq 是离线数学的偏序关系, 若 a == b, 且 b == c, 无法推导出 a == c
    Eq 是离线数学的全序关系, 若 a == b, 且 b == c, 能推导出 a == c

    如果想表达部分相等关系, 则只实现 PartialEq 即可
    如果想表达完全相等关系, 则实现 PartialEq 后, 再用 impl Eq for Book {} 实现默认的 Eq 方法即可

    #[warn(dead_code)]
    fn main() {
        enum BookFormat {
            Paperback,
            Hardback,
            Ebook,
        }
        struct Book {
            isbn: i32,
            format: BookFormat,
        }
        impl PartialEq for Book {
            fn eq(&self, other: &Self) -> bool {
                self.isbn == other.isbn
            }
        }
        impl Eq for Book {}
        let a = Book {
            isbn: 1,
            format: BookFormat::Paperback,
        };
        let b = Book {
            isbn: 1,
            format: BookFormat::Hardback,
        };
        assert!(a == b)
    }
    
    • 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
    fn main() {
        let f1 = 3.14;
        let f2 = 3.15;
        if f1 == f2 {
            println!("same");
        }
        if f1 != f2 {
            println!("not same");
        }
        is_eq(f1); // 编译不通过, 因为 float 仅实现了 PartialEq, 而因为 Nan 无法比较故未实现 Eq
        is_partial_eq(f1);
    }
    
    fn is_eq<T: Eq>(f: T) {}
    fn is_partial_eq<T: PartialEq>(f: T) {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    不同类型也可各自实现 PartialEq, 从而比较 type1 == type2, 但是传递性会有问题, 如下例:

    #[derive(PartialEq)]
    enum BookFormat {
        Paperback,
        Hardback,
        Ebook,
    }
    
    #[derive(PartialEq)]
    struct Book {
        isbn: i32,
        format: BookFormat,
    }
    
    impl PartialEq<BookFormat> for Book {
        fn eq(&self, other: &BookFormat) -> bool {
            self.format == *other
        }
    }
    
    impl PartialEq<Book> for BookFormat {
        fn eq(&self, other: &Book) -> bool {
            *self == other.format
        }
    }
    
    fn main() {
        let b1 = Book { isbn: 1, format: BookFormat::Paperback };
        let b2 = Book { isbn: 2, format: BookFormat::Paperback };
    
        assert!(b1 == BookFormat::Paperback);
        assert!(BookFormat::Paperback == b2);
    
        // The following should hold by transitivity but doesn't.
        assert!(b1 == b2); // <-- PANICS
    }
    
    • 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

    2.1.3 PartialOrd 和 Ord

    PartialOrd 是离线数学的偏序关系, 若 a < b, 且 b < c, 无法推导出 a < c
    Ord 是离线数学的全序关系, 若 a < b, 且 b < c, 能推导出 a < c

    2.1.4 Hash

    #[derive(Hash)]
    struct Rustacean {
        name: String,
        country: String,
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    也可以自定义用某些字段做 Hash, 示例如下:

    use std::hash::{Hash, Hasher};
    
    struct Person {
        id: u32,
        name: String,
        phone: u64,
    }
    
    impl Hash for Person {
        fn hash<H: Hasher>(&self, state: &mut H) {
            self.id.hash(state);
            self.phone.hash(state);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.1.5 From, Into, TryFrom, TryInto

    TryFrom 定义了错误处理:

    pub trait TryFrom<T>: Sized {
        type Error;
    
        // Required method
        fn try_from(value: T) -> Result<Self, Self::Error>;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    struct GreaterThanZero(i32);
    
    impl TryFrom<i32> for GreaterThanZero {
        type Error = &'static str;
    
        fn try_from(value: i32) -> Result<Self, Self::Error> {
            if value <= 0 {
                Err("GreaterThanZero only accepts values greater than zero!")
            } else {
                Ok(GreaterThanZero(value))
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    let big_number = 1_000_000_000_000i64;
    // Silently truncates `big_number`, requires detecting
    // and handling the truncation after the fact.
    let smaller_number = big_number as i32;
    assert_eq!(smaller_number, -727379968);
    
    // Returns an error because `big_number` is too big to
    // fit in an `i32`.
    let try_smaller_number = i32::try_from(big_number);
    assert!(try_smaller_number.is_err());
    
    // Returns `Ok(3)`.
    let try_successful_smaller_number = i32::try_from(3);
    assert!(try_successful_smaller_number.is_ok());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.2 概念

    本质: 表示一组特定的功能
    包含: 方法, 关联类型, 常量

    2.2.1 关联类型

    例如如下自行实现的一个 函数 trait:

    fn main() {
        trait Function<Args> {
            // Args: 输入参数
            type Output; // Output: 关联类型
            fn call(args: Args) -> Self::Output;
        }
    
        struct AddFunction; // 单元结构体, 其内存布局相当于()
    
        // 两个数的加法, 入参为(T, T), 关联类型为 Output = T
        impl<T: std::ops::Add<Output = T>> Function<(T, T)> for AddFunction {
            type Output = T;
            fn call(args: (T, T)) -> Self::Output {
                args.0 + args.1
            }
        }
    
        // 三个数的加法, 入参为(T, T), 关联类型为 Output = T
        impl<T: std::ops::Add<Output = T>> Function<(T, T, T)> for AddFunction {
            type Output = T;
            fn call(args: (T, T, T)) -> Self::Output {
                args.0 + args.1 + args.2
            }
        }
    
        // 虽两种 AddFunction 的泛型实现, 但关联类型 Output 只有一种
        assert_eq!(AddFunction::call((1, 2)), 3);
        assert_eq!(AddFunction::call((1, 2, 3)), 6);
    }
    
    • 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

    2.2.2 关联常量

    // 下文抽象了寄存器访问内存地址
    use std::marker::PhantomData;
    
    fn main() {
        //------如下为定义------
        enum Access {
            Read,
            Write,
            ReadWrite,
        }
        trait MmioReg {
            const OFFSET: usize; // 关联常量
            const ACCESS: Access; // 关联常量
            type Repr: Sized + Copy; // 关联类型 Repr 意为寄存器
    
            fn at(base: std::ptr::NonNull<()>) -> Volatile<Self::Repr> {
                let _address = base.as_ptr() as usize + Self::OFFSET;
                Volatile(Self::ACCESS, PhantomData)
            }
        }
        struct Volatile<T>(Access, std::marker::PhantomData<T>); // struct, 标识用什么方式(Access), 读写一个内存指针(PhantomData)
    
        //------如下为使用------
        struct SampleReg;
        impl MmioReg for SampleReg {
            const OFFSET: usize = 0x100;
            const ACCESS: Access = Access::ReadWrite;
            type Repr = u32;
        }
        let reg = SampleReg::at(std::ptr::NonNull::dangling());
    }
    
    • 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

    2.3.3 泛型关联类型

    trait 内的关联类型, 本身也可以是泛型的

    2.3.3.1 示例: 用泛型关联类型, 创建集合工厂
    fn main() {
        // -------定义trait如下
        trait CollectionFactory {
            type Collection<T>;
            type Iter<'a, T>
            where
                T: 'a;
    
            fn empty<T>() -> Self::Collection<T>;
    
            fn iter<'a, T>(collection: &'a Self::Collection<T>) -> Self::Iter<'a, T>
            where
                T: 'a;
        }
    
        // -------实现trait如下
        struct VecFactory;
        impl CollectionFactory for VecFactory {
            type Collection<T> = Vec<T>;
            type Iter<'a, T> = std::slice::Iter<'a, T> where T: 'a;
    
            fn empty<T>() -> Self::Collection<T> {
                Vec::new()
            }
    
            fn iter<'a, T>(collection: &'a Self::Collection<T>) -> Self::Iter<'a, T>
            where
                T: 'a,
            {
                collection.iter()
            }
        }
    
        // ------使用如下, 传入 T 和 CollectionFactory
        struct Queue<T, F: CollectionFactory> {
            inner: F::Collection<T>,
        }
        let vec_based_queue = Queue::<_, VecFactory> {
            inner: vec![1, 2, 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
    2.3.3.2 在函数式编程中使用泛型关联类型
    fn main() {
        trait Functor<T> {
            type Output<U>: Functor<U>;
            fn fmap<U>(self, f: impl FnOnce(T) -> U) -> Self::Output<U>;
        }
        impl<T> Functor<T> for Option<T> {
            type Output<U> = Option<U>;
            fn fmap<U>(self, f: impl FnOnce(T) -> U) -> Self::Output<U> {
                self.map(f)
            }
        }
        let s = Some(1);
        let s = s.fmap(|x| x + 1);
        assert_eq!(s, Some(2));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    三 生命周期

    本质: 一个结构单元, 其包括了一个变量/类型的存活范围

    fn main() {
        fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
            if x.len() > y.len() {
                x
            } else {
                y
            }
        }
        let l = longest("a", "abc");
        assert_eq!(l, "abc");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    fn main() {
        struct Ref<'a, T>(&'a T);
        let x = 42;
        let y = Ref(&x);
        assert_eq!(y.0, &42);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.1 子类型

    • 生命周期的包含关系: 比 … 活得久(outlive)
      • 结论: 'a: 'b 等价于 'a 比 'b 活得久, 即 a outlives b
      • 定理: 对于任意生命周期 'a, 有 'static: 'a (即 staitc 生命周期 比 a 生命周期 活的更久)
    • 子类型: 可替换性
      • 定义: 'x 是 'y 的子类型
        • 大前提: 对于某处 “不可变引用”, 有对于单个生命周期的要求
        • 小前提: 若 'y 满足该要求
        • 结论: 'x 也满足该要求
      • 暴论: 类型越"子", 可以满足的要求越多
    • 结合以上两组结论, 我们有 'a: 'b 等价于 'a 是 'b 的子类型

    'a 是 'b 的子类型 表示为 偏序关系 <, 'a 与 'b 无关 表示为 'a <> 'b, 则对于任意两个生命周期 'a 和 'b, 仅存在 3 种不等关系, 将这3种关系统称为 R('a, 'b):

    • 'a < 'b, 即 a 是 b 的子类型
    • 'a <> 'b, 即 a 与 b 无关
    • 'a > 'b, 即 b 是 a 的子类型

    则 R 对于泛型的映射

    • 对于单生命周期的泛型 T, 这个映射即定义为 T: R('a, 'b) --> R<'a>, T<'b>), 这个关系有三种:
      • 相同: 即若 'a 是 'b 的子类型, 则 T<'a> 是 T<'b> 的子类型
      • 相反: 即若 'a 是 'b 的子类型, 则 T<'b> 是 T<'a> 的子类型
      • 无关: 即若 'a 是 'b 的子类型, 则 T<'a> 和 T<'b> 无关

    示例如下:

    fn main() {
        struct A<'a>(&'a i32); // A即为一个单生命周期的类型构造器
    
        let x = 1;
        // 外括号的生命周期为'a
        {
            let y: &i32 = &x;
            // 内括号的生命周期为'b
            {
                let z: &i32 = &x;
            }
        }
        // 因为外括号的存活域比内括号的存活域大, 设外括号的生命周期为'a, 设内括号的生命周期为'b
        // 则 'a 是 'b 的子类型
        // 则对于实际构造出的两个引用(y 和 z), 即有 y 是生命周期为'a 的 &i32, z 是生命周期为'b 的 &i32
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    更详细的解释是:

    fn main() {
        struct A<'a>(&'a i32); // A即为一个单生命周期的类型构造器
    
        let x = 1;
        // 外括号的生命周期为'a
        {
            let mut y: &i32 = &x;
            // 内括号的生命周期为'b
            {
                let mut z: &i32 = &x;
                y = z; // 可编译通过
                z = y; // 可编译通过
            }
        }
        // 因为外括号的存活域比内括号的存活域大, 设外括号的生命周期为'a, 设内括号的生命周期为'b
        // 则 'a 是 'b 的子类型
        // 则对于实际构造出的两个引用(y 和 z), 即有 y 是生命周期为'a 的 &i32, z 是生命周期为'b 的 &i32
    
        // 则 y 的生命周期为 'a, z 的生命周期为 'b
        // 则生命周期为 'b 的 &i32, 可以被 生命周期为 'a 的 &i32 替换
        // 生命周期为 'a 的 &i32, 就是生命周期为 'b 的 &i32 (子类型 a 就是父类型 b)
    
        // 构成了一种映射: 若 'a 是 'b 的子类型, 则 &'a &i32 是 &'b &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

    总结三种映射关系如下:

    • 不可变引用, 是协变关系 (示例如上)
      • 如 &'static str 是 &str 的子类型, 即 &'static str 可替换 &str
    • 函数, 是逆变关系
      • 如 fn(&'static str) 并不是 fn(&'x str) 的子类型, 即不能用 fn(&'static str) 替换 fn(&'x str).
      • 但反而 fn(&'x str) 是 fn(&'static str) 的子类型, 即能用 fn(&'x str) 替换 fn(&'static str)
    • 可变引用, 是不变关系

    示例: 如下图即为悬垂引用的示例

    • 用传统 rust 话术是这样解释的: 因为 hello 是 static 生命周期, 而 world 只有 'x 的生命周期, 所以 当将 hello 指向 world 的引用时, rust 编译器会报错: world does not live long enough, 即当 world 走出其作用域而失效时, 会造成 hello 指向悬垂引用:
    • 另一种解释话术如下:

    详见 file:///Users/y/.rustup/toolchains/stable-aarch64-apple-darwin/share/doc/rust/html/nomicon/subtyping.html?highlight=subtyping#subtyping

    3.2 高阶生命周期绑定(HRTB): 泛型的泛型

    四 闭包

    本质: 拥有可能的关联上下文的匿名函数结构体

    fn main() {
        let x = 5;
        let plus_x = |a| a + x;
        assert_eq!(plus_x(5), 10);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    闭包实际展开如下:

    #[test]
    fn expansion() {
        struct Anonymous<'a>(&'a i32);
        impl<'a> Anonymous<'a> {
            // 捕获
            fn new(x: &'a i32) -> Self {
                Anonymous(x)
            }
            // 使用
            fn call(&self, a: i32) -> i32 {
                a + self.0
            }
        }
        let x = 5;
        let plus_x = Anonymous::new(&x);
        assert_eq!(plus_x.call(5), 10);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    4.1 move 关键字: 强制捕获上下文的所有权

    • 不使用 move 时如下:
    #[test]
    fn use_keyword_move() {
        let vec = vec![1, 2, 3];
        {
            let print_borrowed_vec = || println!("{vec:?}"); // 不使用 move 关键字时, 闭包是以引用方式捕获的
            println!("{vec:?}");
            print_borrowed_vec()
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 使用 move 时如下:
    #[test]
    fn use_keyword_move() {
        let vec = vec![1, 2, 3];
        {
            let print_owned_vec = move || println!("{vec:?}");
            println!("{vec:?}"); // 编译报错, 因vec 的所有权已在上一行被转移了
            print_owned_vec();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    move 其实是一个语法糖, 我们也可自己捕获, 如下例是等价的两个闭包:

    fn use_keyword_move() {
        let vec = vec![1, 2, 3];
        // {
        //     let print_owned_vec = move || println!("{vec:?}");
        //     print_owned_vec();
        // }
        {
            let print_owned_vec = || {
                let vec = vec; // vec 捕获了所有权
                println!("{vec:?}");
            };
            print_owned_vec();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.2 闭包的类型推断

    4.3 闭包的 trait 的表示和存储

    // FnOnce 示例如下:
    let print_owned_vec = move || println!("{vec:?}"); // 是FnOnce, 即调用一次就会消耗其所有权
    
    // FnMut 示例如下:
        struct Anonymous<'a>(&'a mut i32); // 是 &mut, 所以每调用一次都会使其上下文发生改变, 则它只实现了 FnMut, 而没有实现 Fn
        impl<'a> Anonymous<'a> {
            // 捕获
            fn new(x: &'a i32) -> Self {
                Anonymous(x)
            }
            // 使用
            fn call(&self, a: i32) -> i32 {
                a + self.0
            }
        }
    
    // Fn 示例如下:
    let plus_x = |a| a + x; // 是Fn, 因为获取的都是不可变引用, 所以其可被无损的调用任意次
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    他们之间是包含关系:

    • 只要实现了 Fn, 则一定也实现了 FnMut 和 FnOnce
    • 只要实现了 FnMut, 则一定也实现了 FnOnce

    4.2.1 示例: 将闭包作为函数参数或返回值

    #[test]
    fn pass_as_parameters_and_return_values() {
        fn plus(x: i32) -> impl Fn(i32) -> i32 {
            move |a| a + x
        }
        fn map<T, U>(value: T, f: impl FnOnce(T) -> U) -> U {
            f(value)
        }
        fn assert_fn_once<F: FnOnce(i32) -> i32>(_: F) {}
        fn assert_fn_mut<F: FnMut(i32) -> i32>(_: F) {}
    
        let x = 5;
        let plus_x = plus(x); // 因为 plus_x 实现了 Fn, 又因为若实现了 Fn 则一定也实现了 FnMut 和 FnOnce
        assert_fn_once(&plus_x); // 所以 plus_x 实现了 FnOnce, 所以此断言通过
        assert_fn_mut(&plus_x);
        assert_eq!(map(2, plus_x), 7);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    4.2.2 示例: 将闭包存储到数据结构中

    
    #[test]
    fn storage() {
        // -----定义:
        struct ServiceBuilder<Opener> {
            params: Option<String>,
            opener: Opener,
        }
        impl<Opener> ServiceBuilder<Opener> {
            fn new(opener: Opener) -> Self {
                Self {
                    params: None,
                    opener,
                }
            }
            fn with_params(mut self, params: String) -> Self {
                self.params = Some(params);
                self
            }
        }
        impl<Service, Opener: FnOnce(String) -> Service> ServiceBuilder<Opener> {
            fn open(self) -> Service {
                let params = self.params.expect("Please input some params");
                (self.opener)(params)
            }
        }
    
        // -----使用:
        let opener = |params| {
            println!("Opening service with params: {params}");
            "mocked service"
        };
        let init_service = ServiceBuilder::new(opener).with_params("Some params".to_string());
        let service = init_service.open();
        println!("Service is {service:?}");
    }
    
    // output result as belows:
    Opening service with params: Some params
    Service is "mocked service"
    test storage ... ok
    
    • 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

    五 迭代器

    本质: 对序列的流失处理–变换或消耗

    5.1 示例: 消耗迭代器进行遍历的基本方法

    #[test]
    fn basic_usage() {
        let array = [1, 2, 3, 4, 5];
        let iter = array.iter();
        for item in iter {
            println!("{item}");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5.2 迭代器的 trait

    5.2.1 示例: 使用 trait 方法消耗迭代器

    #[test]
    fn iterator_traits() {
        let array = [1, 2, 3, 4, 5];
        let mut iter = array.iter();
        assert_eq!(iter.next(), Some(&1));
        assert_eq!(iter.next(), Some(&2));
        assert_eq!(iter.next(), Some(&3));
        assert_eq!(iter.next(), Some(&4));
        assert_eq!(iter.next(), Some(&5));
        assert_eq!(iter.next(), None);
        assert_eq!(iter.next(), None);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    5.2.2 示例: 自定义计数器迭代器

    #[test]
    fn custom_iterator() {
        struct Counter {
            start: i32,
            count: i32,
        }
        impl Iterator for Counter {
            type Item = i32;
            fn next(&mut self) -> Option<Self::Item> {
                if self.count > 0 {
                    let ret = self.start;
                    self.start += 1;
                    self.count -= 1;
                    Some(ret)
                } else {
                    None
                }
            }
        }
        let mut counter = Counter { start: 3, count: 5 };
        for item in counter {
            println!("{item}",);
        }
    }
    
    // code result:
    3
    4
    5
    6
    7
    
    • 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

    5.3.3 展开 for 循环

    
    #[test]
    fn expand_for_loop() {
        let array = [1, 2, 3, 4, 5];
        for item in array.iter() {
            println!("{item}");
        }
    
    	// 可展开为 while let
        {
            let mut iter = array.iter();
            while let Some(item) = iter.next() {
                println!("{item}");
            }
        }
    
    	// 也可展开为 loop match
        let mut iter = array.iter();
        loop {
            match iter.next() {
                Some(item) => println!("{item}"),
                None => break,
            }
        }
    }
    
    • 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

    5.4 迭代器的变换和消耗

    迭代器是 rust 函数式编程经常使用的场合

    5.4.1 示例: 变换和消耗

    fn main() {
        struct Person {
            name: String,
            age: i32,
        }
        let people = [
            Person {
                name: "Alice".to_string(),
                age: 21,
            },
            Person {
                name: "Bob".to_string(),
                age: 25,
            },
            Person {
                name: "Charlie".to_string(),
                age: 18,
            },
            Person {
                name: "Dave".to_string(),
                age: 30,
            },
            Person {
                name: "Eve".to_string(),
                age: 28,
            },
            Person {
                name: "Frank".to_string(),
                age: 32,
            },
        ];
        let student_ids = [1001, 1002, 1003, 1004, 1005, 1006];
    
        let all_names = people.iter().map(|p| p.name.clone()).collect::<Vec<_>>();
        println!("{:?}", all_names);
    
        // let first_3_student_ids_whose_age_is_over_21
        let mut first_3_student_ids_whose_age_is_over_21 = Vec::new();
        for index in 0..6 {
            let person = &people[index];
            let id = student_ids[index];
            if person.age > 21 {
                first_3_student_ids_whose_age_is_over_21.push(id);
                if first_3_student_ids_whose_age_is_over_21.len() == 3 {
                    break;
                }
            }
        }
        assert_eq!(first_3_student_ids_whose_age_is_over_21, [1002, 1004, 1005]);
        let first_3_student_ids_whose_age_is_over_21 = people
            .iter()
            .zip(student_ids.iter())
            //.filter(|(p, _)| p.age > 21)
            //.map(|(_, id)| *id).
            .filter_map(|(p, &id)| (p.age > 21).then_some(id))
            .take(3)
            .collect::<Vec<_>>();
        assert_eq!(first_3_student_ids_whose_age_is_over_21, [1002, 1004, 1005]);
    }
    
    • 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

    5.4.2 迭代器的性能

    迭代器性能很好, 程序员不需要为了性能而使用 for, 使用 迭代器即可兼顾性能和可读性

    六 智能指针

    fn main() {}
    #[test]
    fn basic_usage() {
        let x = 5;
        let boxed_x = Box::new(x); // Box将无法在编译期确定大小的东西, 变为可在编译器确定大小
        let y = *boxed_x; // 解引用
        let z = *boxed_x;
        assert_eq!(y, z);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • Box
    use std::collections::HashMap;
    fn main() {}
    #[test]
    fn basic_usage() {
        let x = 5;
        let boxed_x = Box::new(x);
        let y = *boxed_x;
        let z = *boxed_x;
        assert_eq!(y, z);
    
        let array = [1, 2, 3, 4, 5];
        let mut iter = Box::new(array.into_iter()) as Box<dyn Iterator<Item = i32>>;
        let hash_map = [(1, ()), (2, ())].into_iter().collect::<HashMap<_, _>>();
        iter = Box::new(hash_map.into_keys());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • vec
    fn main() {}
    #[test]
    fn basic_usage() {
        let x = 5;
        let boxed_x = Box::new(x);
        let y = *boxed_x;
        let z = *boxed_x;
        assert_eq!(y, z);
    
        let array = [1, 2, 3, 4, 5];
        let slice = &array[1..3];
        let vec = slice.to_vec();
        let vec_slice = &vec[..];
        assert_eq!(vec_slice, slice);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • String
    fn main() {}
    #[test]
    fn basic_usage() {
        let x = 5;
        let boxed_x = Box::new(x);
        let y = *boxed_x;
        let z = *boxed_x;
        assert_eq!(y, z);
    
        let s = "Hello world";
        let s_slice = &s[1..3];
        let string = s.to_string();
        let string_slice = &string[1..3];
        assert_eq!(string_slice, s_slice);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    6.1 智能指针的特征

    源码中 String 的 Deref 实现如下:

    • 自己实现的 智能指针 Smart 如下, 主要是实现了 Deref trait:
    use std::ops::Deref;
    
    fn main() {}
    
    #[test]
    fn custom_smart_pointers() {
        struct Smart<T>(T);
        impl<T> Smart<T> {
            fn new(value: T) -> Self {
                Self(value)
            }
        }
        impl<T> Deref for Smart<T> {
            type Target = T;
            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }
        let smart = Smart::new(5);
        assert_eq!(*smart, 5)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 自己实现的 智能指针 Smart 如下, 除了实现 Deref trait, 还实现了 DerefMut trait:
    use std::ops::{Deref, DerefMut};
    
    fn main() {}
    
    #[test]
    fn custom_smart_pointers() {
        struct Smart<T>(T);
        impl<T> Smart<T> {
            fn new(value: T) -> Self {
                Self(value)
            }
        }
        impl<T> Deref for Smart<T> {
            type Target = T;
            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }
        impl<T> DerefMut for Smart<T> {
            fn deref_mut(&mut self) -> &mut Self::Target {
                &mut self.0
            }
        }
        let mut smart = Smart::new(5);
        assert_eq!(*smart, 5);
        *smart = 10;
        assert_eq!(*smart, 10);
    }
    
    • 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

    6.2 智能指针的引用计数RC

    use std::rc::Rc;
    
    fn main() {
        let c = Node::new(1, None);
        let b = Node::new(2, Some(Rc::clone(&c)));
        let a = Node::new(3, Some(Rc::clone(&b)));
        let x = Node::new(4, Some(Rc::clone(&a)));
        let y = Node::new(5, Some(Rc::clone(&a)));
        // 因为 x 和 y 都共享 a, 所以有两条链表, 分别是 xabc 和 yabc
        let vec_x = x.to_vec();
        assert_eq!(vec_x, vec![4, 3, 2, 1]);
        let vec_y = y.to_vec_iterated();
        assert_eq!(vec_y, vec![5, 3, 2, 1]);
    }
    
    struct Node<T> {
        data: T,
        next: Option<Rc<Node<T>>>,
    }
    
    impl<T> Node<T> {
        fn new(data: T, next: Option<Rc<Node<T>>>) -> Rc<Self> {
            Rc::new(Node { data, next })
        }
        fn to_vec(self: &Rc<Self>) -> Vec<T>
        where
            T: Clone,
        {
            let mut vec = Vec::new();
            let mut node = Some(Rc::clone(self));
            while let Some(n) = node {
                vec.push(n.data.clone());
                node = n.next.as_ref().map(Rc::clone);
            }
            vec
        }
        // -----使用迭代器如下:
        fn to_vec_iterated(self: &Rc<Self>) -> Vec<T>
        where
            T: Clone,
        {
            let mut node = Some(Rc::clone(self));
            let iter = std::iter::from_fn(move || match node.take() {
                Some(n) => {
                    node = n.next.as_ref().map(Rc::clone);
                    Some(n.data.clone())
                }
                None => None,
            });
            iter.collect()
        }
    }
    
    • 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

    6.3 内部可变性

    fn main() {}
    
    #[test]
    fn interior_mutability() {
        #![allow(unused)]
        trait MessageSender {
            fn send(&self, message: String); // &self 是不可变引用
        }
        struct Validator<M: MessageSender>(M);
    
        impl<M: MessageSender> Validator<M> {
            fn validate(&self, value: &i32) {
                if !(-10..10).contains(value) {
                    self.0
                        .send(format!("Value {} is not in range [-10, 10]", value));
                }
            }
        }
    
        struct MockMessageSender {
            messages: Vec<String>,
        }
    
        impl MessageSender for MockMessageSender {
            fn send(&self, message: String) {
                self.messages.push(message); // 因为需要调用 push(), 所以需要 self 内部的 messages 是可变的, 而 &self 本身是不可变引用, 所以需要内部可变性
            }
        }
    }
    
    • 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

    6.3.1 RefCell

    本质是先在编译期通过, 但运行时如果发生错误仍会直接 panic(), 所以非常坏的一种实践

    6.3.3.1 示例: 上例使用 RefCell 的效果

    6.3.3.2 示例: 使用 Rc + RefCell 实现双向链表

    七 并发与并行

    7.1 进程和线程

    • 示例: 使用 std::thread 创建线程, 使用 JoinHandle() 等待线程完成
    use std::thread;
    
    fn main() {}
    
    #[test]
    fn use_multithread() {
        let thread = thread::spawn(|| {
            for i in 0..10 {
                println!("thread: {}", i);
            }
        });
        for i in 0..10 {
            println!("main: {}", i);
        }
        thread.join().unwrap();
    }
    
    // code result:
    main: 0
    main: 1
    main: 2
    main: 3
    main: 4
    main: 5
    main: 6
    main: 7
    main: 8
    main: 9
    thread: 0
    thread: 1
    thread: 2
    thread: 3
    thread: 4
    thread: 5
    thread: 6
    thread: 7
    thread: 8
    
    • 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
    • 示例: 使用 move 在多线程间用闭包捕获所有权
    use std::thread;
    
    fn main() {}
    
    #[test]
    fn move_between_threads() {
        let vec = vec![1, 2, 3, 4, 5];
        let thread = thread::spawn(move || {
            let mut vec = vec;
            vec.push(6);
            println!("{vec:?}");
        });
        // println!("{vec:?}"); // 此处无法再使用 vec, 因为其所有权已被 move 到线程里了
        thread.join().unwrap();
    }
    
    // code result:
    [1, 2, 3, 4, 5, 6]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    7.2 多线程数据访问: 消息传递

    uuse std::{sync::mpsc, thread};
    
    fn main() {}
    
    #[test]
    fn mpsc_channels() {
        let (tx, rx) = mpsc::channel();
        for t in 0..10 {
            let tx = tx.clone();
            thread::spawn(move || {
                for i in 0..3 {
                    let num = 100 * t + i;
                    tx.send(num).unwrap();
                }
            });
        }
        drop(tx); // drop main()函数中的 tx
                  // 当所有发送端都发送完毕后, 则 mpsc 的所有 rx 都会自动 drop, 则rx.recv() 会返回 Err
        while let Ok(num) = rx.recv() {
            println!("{}", num);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    7.3 多线程数据访问: 状态共享

    use std::{
        sync::{mpsc, Mutex},
        thread,
        time::Duration,
    };
    
    fn main() {}
    
    #[test]
    fn mutexes() {
        static DATA: Mutex<i32> = Mutex::new(0);
        thread::spawn(|| {
            for i in 0..10 {
                *DATA.lock().unwrap() += i;
                thread::sleep(Duration::from_secs(1));
            }
        });
        while *DATA.lock().unwrap() < 45 {
            println!("Waiting");
            thread::sleep(Duration::from_secs(1));
        }
    }
    
    // code result: 打印 10 次 Waiting 后值大于 45, 故退出 main() 函数
    running 1 test
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    test mutexes ... ok
    
    • 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

    7.4 多线程相关 trait: Send 和 Sync

    7.4.1 使用 Arc 智能指针

    Arc 即 Atomic 的 Rc, 可在线程间使用

    use std::{
        sync::{mpsc, Mutex, Arc},
        thread,
        time::Duration,
    };
    
    fn main() {}
    
    #[test]
    fn arc_usage() {
        let data = Arc::new(Mutex::new(0));
        let d2 = data.clone();
    
        thread::spawn(move || {
            for i in 0..10 {
                *d2.lock().unwrap() += i;
                thread::sleep(Duration::from_secs(1));
            }
        });
        while *data.lock().unwrap() < 45 {
            println!("Waiting");
            thread::sleep(Duration::from_secs(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

    Arc 源码如下:

    八 unsafe Rust

    unsafe 块一定要写注释, 示例如下:

    8.1 裸指针 *const T 和 *mut T

    8.2 ManuallyDrop

    8.3 NonNull

    8.4 MaybeUninit

    8.5 其他函数和方法

  • 相关阅读:
    【C++】C 语言 和 C++ 语言中 const 关键字分析 ( const 关键字左数右指原则 | C 语言中常量的原理和缺陷 | C++ 语言中常量原理 - 符号表存储常量 )
    栈Stack
    ORACLE11g Dataguard物理Standby-日常巡检操作手册
    vue是怎么实现数据响应式的?
    深度学习面试题目01
    工程水文学试卷
    计算机二级WPS 选择题(模拟和解析五)
    redis 哨兵 sentinel(二) 哨兵原理
    [PostgreSQL的 SPI_接口函数]
    浅谈 @Autowired 和 @Resource 的区别
  • 原文地址:https://blog.csdn.net/jiaoyangwm/article/details/133980073