├── .gitignore ├── LICENSE ├── README.md ├── Rust_ebooks └── Programming Rust 2nd Edition Covers Rust 1.50 - Jim Blandy.pdf ├── Rust学习笔记_基础 ├── rust快查手册.md ├── unsafe和外部函数调用 │ ├── rust_c.md │ └── unsafe.md ├── 内存管理 │ ├── README.md │ ├── gc.jpeg │ ├── imgs │ │ ├── enum_e.png │ │ ├── move.png │ │ ├── 内存对齐_1.png │ │ ├── 内存布局_1.png │ │ ├── 结构体A.png │ │ └── 虚拟内存空间.png │ ├── rust资源管理.md │ ├── 内存布局.md │ ├── 内存管理.md │ └── 通用概念.md ├── 内部实现.md ├── 内部实现_img │ ├── access_to_non-owned_memory.jpg │ ├── am.jpg │ ├── application_memory.jpg │ ├── array.jpg │ ├── borrowed_state.jpg │ ├── closures.jpg │ ├── dst.jpg │ ├── empty_struct.jpg │ ├── enum.jpg │ ├── f32.jpg │ ├── function_boundaries.jpg │ ├── function_parameters.jpg │ ├── general_purpose_heap_storage.jpg │ ├── lifetime_of_things.jpg │ ├── lifetimes_propagate_borrowed_state.jpg │ ├── meaning_of_r.jpg │ ├── moves.jpg │ ├── mutex.jpg │ ├── nested_functions.jpg │ ├── numeric_types.jpg │ ├── owned_strigns.jpg │ ├── owned_strings.jpg │ ├── pointer_meta.jpg │ ├── problem_of_borrowed_propagation.jpg │ ├── raw_pointers.jpg │ ├── rc.jpg │ ├── references_as_pointers.jpg │ ├── references_pointers.jpg │ ├── repurposing_memory.jpg │ ├── scope_drop.jpg │ ├── sized.jpg │ ├── slice.jpg │ ├── standard_library_types.jpg │ ├── struct.jpg │ ├── textual_types.jpg │ ├── tuple.jpg │ ├── type_safety.jpg │ ├── typelinkeness_of_lifetimes.jpg │ ├── union.jpg │ ├── unlocking.jpg │ └── variable.jpg ├── 函数 │ ├── 函数.md │ └── 闭包 │ │ ├── base.jpg │ │ ├── 作为参数.md │ │ ├── 作为返回值.md │ │ └── 闭包.md ├── 包 │ ├── 包 │ │ └── 包.md │ ├── 导入.md │ ├── 工作空间 │ │ └── 工作空间.md │ ├── 模块 │ │ └── 模块.md │ └── 箱 │ │ └── 箱.md ├── 宏和元编程 │ ├── 元编程.md │ └── 宏.md ├── 对象 │ ├── 复制 │ │ └── 复制.md │ ├── 方法 │ │ └── 方法.md │ ├── 析构 │ │ └── 析构.md │ ├── 泛型 │ │ ├── phantomType.md │ │ └── 泛型.md │ ├── 特征 │ │ ├── 传递 │ │ │ └── 传递.md │ │ ├── 关联 │ │ │ ├── 关联.md │ │ │ └── 关联_实例.md │ │ ├── 其它.md │ │ ├── 同名 │ │ │ └── 同名.md │ │ ├── 多态 │ │ │ └── 多态.md │ │ ├── 操作符 │ │ │ └── 操作符.md │ │ ├── 泛型 │ │ │ └── 泛型.md │ │ ├── 特征.md │ │ ├── 特征区间.md │ │ ├── 特征对象.md │ │ ├── 特征对象和对象安全性.md │ │ └── 继承 │ │ │ └── 继承.md │ └── 迭代器 │ │ └── 迭代器.md ├── 工具 │ ├── 工具.md │ └── 环境问题.md ├── 并发 │ ├── README.md │ ├── actor.jpg │ ├── actor.md │ ├── 同步 │ │ └── 同步.md │ ├── 并行 │ │ ├── README.md │ │ ├── scalar.jpg │ │ ├── simd.jpg │ │ ├── 垂直计算.jpg │ │ ├── 水平计算.jpg │ │ └── 计算机系统结构.jpg │ ├── 异步 │ │ ├── Future │ │ │ ├── Pin和Unpin.md │ │ │ ├── README.md │ │ │ ├── imgs │ │ │ │ └── Future调度流程图.png │ │ │ ├── move.jpg │ │ │ ├── move_swap.jpg │ │ │ └── waker.md │ │ ├── README.md │ │ ├── async_await │ │ │ ├── README.md │ │ │ ├── async和await.md │ │ │ ├── imgs │ │ │ │ ├── TCP-IP详解卷1:协议.pdf │ │ │ │ ├── future.png │ │ │ │ └── future2.png │ │ │ └── pin应用.md │ │ └── yield │ │ │ ├── README.md │ │ │ └── 生成器执行流程图.png │ ├── 消息 │ │ └── 消息.md │ ├── 线程 │ │ ├── Actor模型.png │ │ ├── README.md │ │ ├── Rayon.md │ │ ├── atomic.md │ │ ├── barrier.md │ │ ├── channel.md │ │ ├── channel.png │ │ ├── convar.md │ │ ├── crossbeam.md │ │ ├── mutex.md │ │ ├── rwlock.md │ │ ├── send_sync.md │ │ ├── thread_pool.md │ │ ├── thread_pool_example.rs │ │ ├── unsafeCell.md │ │ ├── 代码执行流程.png │ │ ├── 多线程并发编程.md │ │ └── 线程.md │ └── 线程的并发模型.md ├── 所有权 │ ├── Borrow.md │ ├── README.md │ ├── moveship_copy_stack.png │ ├── 引用和借用.md │ ├── 所有权.md │ └── 生命周期.md ├── 数据 │ ├── 全局值.md │ ├── 切片 │ │ └── 切片.md │ ├── 向量 │ │ └── 向量.md │ ├── 字符串 │ │ ├── encode.png │ │ ├── 字符串.md │ │ ├── 字符串_String.md │ │ ├── 字符串_str.md │ │ └── 字符编码.md │ ├── 指针 │ │ ├── cow.md │ │ ├── ptr.png │ │ ├── 指针.md │ │ └── 智能指针.md │ ├── 枚举 │ │ └── 枚举.md │ ├── 结构 │ │ └── 结构.md │ └── 联合 │ │ └── 联合.md ├── 测试 │ ├── 单元测试 │ │ └── 单元测试.md │ └── 基准测试 │ │ └── 基准测试.md ├── 类型 │ ├── 别名.md │ ├── 变量.md │ ├── 常量.md │ ├── 类型.md │ ├── 类型大小.md │ ├── 类型转换 │ │ ├── From和Into.md │ │ ├── ToString和FromStr.md │ │ └── TryFrom和TryInto.md │ └── 转换.md ├── 表达式 │ ├── 控制流.md │ ├── 模式匹配.md │ ├── 表达式.md │ └── 迭代器.md ├── 进阶 │ ├── 宏 │ │ └── 宏.md │ └── 注释 │ │ └── 注释.md ├── 错误 │ ├── README.md │ ├── panic.png │ ├── 不可恢复错误.md │ ├── 可恢复错误.md │ └── 异常处理.md └── 附录 │ ├── imgs │ ├── ir.jpg │ └── rust编译过程.png │ ├── 安装.md │ ├── 版本.md │ ├── 编译.md │ └── 资源.md ├── Rust学习笔记_库 ├── Rust构建Web应用程序 │ └── hyper │ │ ├── hyper.md │ │ ├── hyperurl │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── main.rs │ │ │ ├── service.rs │ │ │ └── shortener.rs │ │ └── shorten │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs ├── Rust网络编程 │ ├── README.md │ ├── 异步网络IO.md │ └── 构建同步Redis服务器.md ├── exercises │ ├── advanced_errors │ │ ├── advanced_errs1.rs │ │ └── advanced_errs2.rs │ ├── clippy │ │ ├── README.md │ │ ├── clippy1.rs │ │ └── clippy2.rs │ ├── collections │ │ ├── README.md │ │ ├── hashmap1.rs │ │ ├── hashmap2.rs │ │ ├── vec1.rs │ │ └── vec2.rs │ ├── conversions │ │ ├── README.md │ │ ├── as_ref_mut.rs │ │ ├── from_into.rs │ │ ├── from_str.rs │ │ ├── try_from_into.rs │ │ └── using_as.rs │ ├── enums │ │ ├── README.md │ │ ├── enums1.rs │ │ ├── enums2.rs │ │ └── enums3.rs │ ├── error_handling │ │ ├── README.md │ │ ├── errors1.rs │ │ ├── errors2.rs │ │ ├── errors3.rs │ │ ├── errors4.rs │ │ ├── errors5.rs │ │ └── errors6.rs │ ├── functions │ │ ├── README.md │ │ ├── functions1.rs │ │ ├── functions2.rs │ │ ├── functions3.rs │ │ ├── functions4.rs │ │ └── functions5.rs │ ├── generics │ │ ├── README.md │ │ ├── generics1.rs │ │ ├── generics2.rs │ │ └── generics3.rs │ ├── if │ │ ├── RADEME.md │ │ ├── if1.rs │ │ └── if2.rs │ ├── macros │ │ ├── README.md │ │ ├── macros1.rs │ │ ├── macros2.rs │ │ └── macros3.rs │ ├── modules │ │ ├── README.md │ │ ├── modules1.rs │ │ ├── modules2.rs │ │ └── modules3.rs │ ├── move_semantics │ │ ├── README.md │ │ ├── move_semantics1.rs │ │ ├── move_semantics2.rs │ │ ├── move_semantics3.rs │ │ └── move_semantics4.rs │ ├── options │ │ ├── README.md │ │ ├── option1.rs │ │ ├── option2.rs │ │ └── option3.rs │ ├── primitive_types │ │ ├── README.md │ │ ├── primitive_type4.rs │ │ ├── primitive_type5.rs │ │ ├── primitive_type6.rs │ │ ├── primitive_types1.rs │ │ ├── primitive_types2.rs │ │ └── primitive_types3.rs │ ├── quiz1.rs │ ├── quiz2.rs │ ├── quiz3.rs │ ├── quiz4.rs │ ├── standard_library_types │ │ ├── README.md │ │ ├── arc1.rs │ │ ├── box1.rs │ │ ├── iterators1.rs │ │ ├── iterators2.rs │ │ ├── iterators3.rs │ │ ├── iterators4_fold.rs │ │ ├── iterators4_if.rs │ │ ├── iterators4_imp.rs │ │ ├── iterators4_match.rs │ │ ├── iterators4_product.rs │ │ └── iterators5.rs │ ├── strings │ │ ├── README.md │ │ ├── strings1.rs │ │ └── strings2.rs │ ├── structs │ │ ├── README.md │ │ ├── structs1.rs │ │ ├── structs2.rs │ │ └── structs3.rs │ ├── tests │ │ ├── README.md │ │ ├── tests1.rs │ │ ├── tests2.rs │ │ └── tests3.rs │ ├── threads │ │ ├── README.md │ │ └── threads1.rs │ ├── traits │ │ ├── README.md │ │ ├── traits1.rs │ │ └── traits2.rs │ └── variables │ │ ├── README.md │ │ ├── variables1.rs │ │ ├── variables2.rs │ │ ├── variables3.rs │ │ ├── variables4.rs │ │ ├── variables5.rs │ │ └── variables6.rs └── 日志 │ ├── README.md │ ├── rust日志记录.md │ ├── rust日志记录_log4rs.md │ └── rust日志记录_slog.md ├── SECURITY.md ├── imgs ├── gcc_rust.png ├── rust-for-linux.jpg └── rust_01.jpeg ├── linux-cves-in-2018.png ├── png-transparent-rust-programming-language-logo-machine-learning-haskell-crab-animals-cartoon-crab.png ├── rust.svg ├── rust_board.png ├── rust_facebook.jpeg ├── rust_language.jpeg ├── rust_playground.png └── wechat.jpeg /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | .DS_Store 12 | change_author.sh 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 xuesong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Rust_ebooks/Programming Rust 2nd Edition Covers Rust 1.50 - Jim Blandy.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust_ebooks/Programming Rust 2nd Edition Covers Rust 1.50 - Jim Blandy.pdf -------------------------------------------------------------------------------- /Rust学习笔记_基础/内存管理/gc.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内存管理/gc.jpeg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内存管理/imgs/enum_e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内存管理/imgs/enum_e.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/内存管理/imgs/move.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内存管理/imgs/move.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/内存管理/imgs/内存对齐_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内存管理/imgs/内存对齐_1.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/内存管理/imgs/内存布局_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内存管理/imgs/内存布局_1.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/内存管理/imgs/结构体A.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内存管理/imgs/结构体A.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/内存管理/imgs/虚拟内存空间.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内存管理/imgs/虚拟内存空间.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/内存管理/内存布局.md: -------------------------------------------------------------------------------- 1 | # 内存布局 2 | 3 | **内存中数据的排列方式称为内存布局**。不同的排列方式,占用的内存不同,也会间接影响CPU访问内存的效率。为了权衡空间占用情况和访问效率,引入了内存对齐规则。 4 | 5 | CPU在单位时间内能处理的一组二进制数称为**字**,这组二进制数的位数称为**字长**。如果是32位CPU,字长为32位,也就是4个字节。一般来说,字长越大,计算处理信息的速度就越快,例如,64位CPU就比32位CPU效率更高。 6 | 7 | 32位CPU每次只能读取4字节的数据,所以每次只能对4的倍数的地址进行读取。 8 | 9 |   10 | 11 | ## 内存对齐案例 12 | 13 | 有一整数类型的数据,首地址并不是4的倍数,比如是0x3,则该类型存储在地址范围是`0x3~0x7`的存储空间中。因此,CPU如果想读取该数据,需要分别在0x1和0x5处进行两次读取,而且还需要对读取到的数据进行处理才能得到该整数。CPU的处理速度比从内存中读取数据的速度要快的多,因此,减少CPU对内存空间的访问是提高程序性能的关键。 14 | 15 | ![内存对齐](./imgs/内存布局_1.png) 16 | 17 | 采用内存对齐策略是提高程序性能的关键。所以只需要按4字节对齐,CPU只需要读取一次。 18 | 19 | ![内存对齐](./imgs/内存对齐_1.png) 20 | 21 | 内存是按字节对齐,所有内存对齐也叫字节对齐。内存对齐是编译器或虚拟机(比如JVM)的工作,一些语言不需要人为干预,Rust默认情况下编译器自动对齐(并不是所有语言都会自动对齐),如果是数据结构,会对结构体字段进行重排,重排是编译器的优化手段之一,用来避免内存浪费。 22 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/内存管理/内存管理.md: -------------------------------------------------------------------------------- 1 | # 内存管理 2 | 3 | 可以按照内存管理需求将编程语言大致分为两类:**手动内存管理类和自动内存管理类。** 4 | 5 | **手动内存管理**需要程序员使用 `malloc` 和 `free` 等函数显式管理内存,像C语言。 6 | 7 | **自动内存管理**需要使用`GC(Garbage Collection,垃圾回收)`来对内存进行自动化管理,而无须开发者手动开辟和释放内存,比如 `Java`、`C#`、`Ruby`、`Python` 等语言都是靠 `GC` 自动化管理内存的。 8 | 9 | 通过对手动内存管理和自动内存管理比较,编程语言选择就是,对性能要求高并且需要对内存进行精确操控的系统级开发,一般会选择 `C`和`C++`之类的语言,但存在的问题就是,稍微不注意可能导致内存不安全的问题;其它类型的开发就选择 `Java`、`Python`、`Go` 之类的高级语言,一般不会出现内存不安全的问题,但是它们的性能却降低不少。 10 | 11 | 针对以上两种方式存在的问题Rust取了一个中间点,既不需要程序员手工进行申请/释放内存,也不会有自动内存管理GC导致的`Stop The World`。 12 | 13 |   14 | 15 | ## 手动内存管理 16 | 17 | 手动内存管理的优势在于性能,因为可以直接操控内存,但同时也带来了不少问题。 18 | 19 |   20 | 21 | ### 内存泄漏 22 | 23 | 忘记内存释放,就会带来内存泄漏的问题。 24 | 25 |   26 | 27 | ### 悬垂指针(Dangling Pointer) 28 | 29 | 如果某个指针引用的内存被非法释放掉了,而该指针依旧指向被释放的内存,这种情况下的指针就叫悬垂指针。如果将悬垂指针分配给某个其他的对象,将会产生无法预料的后果。 30 | 31 |   32 | 33 | ## 自动内存管理 34 | 35 | GC自动内存管理接管了程序员分配和回收内存的任务,帮助提升了代码的抽象度和可靠性。GC使用了各种精确的算法来解决内存分配和回收的问题,但并不代表能解决所有问题。GC最大的问题是会引起`Stop The World`,GC在工作的时候必须保证程序不会引入新的「垃圾」,所以要使运行中的程序暂停,会造成性能问题。 36 | 37 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/内存管理/通用概念.md: -------------------------------------------------------------------------------- 1 | # 通用概念 2 | 3 | ## 虚拟内存空间 4 | 5 | 现代操作系统在保护模式下都采用虚拟内存管理技术。虚拟内存是一种对物理存储设备的统一抽象,其中物理存储设备包括物理内存、磁盘、寄存器、高速缓存等。统一抽象的好处是,方便同时运行多道程序,使得每个进程都有各自独立的进程地址空间,并且可以通过操作系统调度将外存当作内存来使用。 6 | 7 | 虚拟地址空间是线性空间,用户所接触到的地址都是虚拟地址,而不是真实的物理地址。利用这种虚拟地址不但能保护操作系统,让程序在各自的地址空间内操作内存,更重要的是,用户程序可以使用比物理内存更大的地址空间。虚拟地址空间被分为两部分:**用户空间和内核空间**,它们的比例是3:1。 8 | 9 | ![虚拟地址空间](./imgs/虚拟内存空间.png) 10 | 11 | 上图为虚拟内存示意图,栈空间向下(由高地址向低地址)增长,堆向上(由低地址向高地址)增长,这样设计为了更高效地利用内存。 12 | 13 |   14 | 15 | ## 栈(Stack) 16 | 17 | 栈一般有两种定义,一种是指**数据结构**,一种是指**栈内存**。操作栈的一端被称为**栈顶**,相反的一端被称为**栈底**。从栈顶压入数据叫**入栈(push)**,从栈顶弹出数据叫**出栈(pop)**,这意味着最后一个入栈的数据会第一个出栈,所以栈被称为**后进先出(LIFO, Last in First Out)** 线性表。 18 | 19 | 物理内存本身不区分堆和栈,但是虚拟内存空间需要分出一部分内存,用于支持CPU入栈或出栈的指令操作,这部分内存空间就是栈空间。栈内存拥有和栈数据结构相同的特性,支持入栈和出栈操作,数据压入的操作使栈顶的地址减少,数据弹出的操作使栈顶的地址增多。 20 | 21 | 栈顶由栈指针寄存器ESP保存,起初栈顶指向栈底位置,当有数据入栈时,栈顶地址向下增长,地址由高地址变成低地址;当有数据被弹出时,栈顶地址向上增长,地址由低地址变成高地址。因此,降低ESP的地址等价于开辟栈空间,增加ESP的地址等价于回收栈空间。 22 | 23 | **栈内存最重要的作用时在程序运行过程中保存函数调用所要维护的信息**。存储每次函数调用所需信息的记录单位被称为**栈帧(Stack Frame)**,有时也被称为活动记录(Activate Record)。因此栈内存被栈帧分割成了N个记录中,而且这些记录块都是大小不一的。 24 | 25 |   26 | 27 | ### 栈帧 28 | 29 | 栈帧一般包括三方面的内容: 30 | 31 | * 函数的返回地址和参数。 32 | * 临时变量。包括函数内部的非静态局部变量和编译器产生的临时变量。 33 | * 保存的上下文(IP、SP、BP)。 34 | 35 | BP指针是帧指针(Frame Pointer),它指向当前栈帧的一个固定位置(栈底),SP始终指向栈顶。BP指向的值是调用函数之前的旧的BP值,这样在函数返回的时候,旧可以通过该值恢复到调用前的值。 36 | 37 | 栈上分配的值都是可以预先确定大小的类型。当函数结束调用的时候,栈帧会被自动释放,所以栈上的数据的生命周期都是在一个函数调用周期内的。 38 | 39 |   40 | 41 | ## 堆(heap) 42 | 43 | 堆(heap)一般也有两种定义,一种是指数据结构,另一种是堆内存。 44 | 45 | 数据结构中,堆表示一种特殊的树形数据结构,此树是一棵完全二叉树,它的特点是父节点的值要么都大于两个子节点的值,称为**大顶堆**;要么都小于两个子节点的值,称为**小顶堆**。一般用于实现堆排序或优先级队列。**堆数据结构和堆内存并无直接的联系**。 46 | 47 | 栈内存中保存的数据,生命周期都比较短,会随着函数调用的完成而消亡。但很多情况下会需要能对长久保存在内存中的数据,以便跨函数使用,这就是堆内存发挥作用的地方。堆内存是一块巨大的内存空间,占了虚拟内存空间的绝大部分。程序不可以主动申请栈内存,但可以主动申请堆内存。在堆内存中存放的数据会在程序中一直存在,除非该内存被主动释放掉。 48 | 49 | 在C语言中,可以通过`malloc`函数来申请堆内存,通过`free`函数释放它;在C++中,可以使用`new`和`delete`进行操作。 50 | 51 | 堆是一大块内存空间,程序通过`malloc`申请到内存空间是大小不一、不连续且无序的,所以如何管理堆内存是一个问题。这就涉及到堆分配算法,堆分配算法由很多种,可以分为两大类: **空闲链表(Free List)** 和 **位图标记(Bitmap)**。 52 | 53 |   54 | 55 | ### 空闲链表 56 | 57 | 空闲链表实际上就是把堆中空闲的内存地址记录为链表,当系统收到程序申请时,会遍历该链表;当找到合适的空间堆节点时,会将此节点从链表中删除;当空间被回收以后,再将其加到空闲链表中。空闲链表优势是实现简单,但如果链表遭到破坏,整个堆就无法正常工作。 58 | 59 |   60 | 61 | ### 位图标记 62 | 63 | 位图的核心思想是将整个堆划分为大量大小相等的块。当程序申请内存时,总是分配整个块的空间。每块内存都有一个二进制来表示其状态,如果该内存被占用,则相应位图中的位置为1;如果该内存空闲,则相应位图中的位置置为0。位图优势速断快,如果单个内存块数据遭到破坏,也不影响整个堆,但缺点是容易产生碎片。 64 | 65 |   66 | 67 | ### Rust 内存分配与回收 68 | 69 | Rust编译器目前自带两个默认分配器: `alloc_system` 和 `alloc_jemalloc`。在Rust 2015版本中,编译器产生的二进制文件默认使用`alloc_jemalloc`,而对于静态或动态链接库,默认使用`alloc_system`。在Rust 2018版本下,默认使用 `alloc_system`,并且可以由开发者自己指派`Jemalloc`或其它第三方分配器。 70 | 71 | Jemalloc 的优势有以下几点: 72 | 73 | * 分配或回收内存更快速 74 | * 内存碎片更少 75 | * 多核友好 76 | * 良好的可伸缩性 77 | 78 | Jemalloc是现代化的业界流行的内存分配解决方案,它整块批发内存(称为chunk)以供程序使用,而非频繁地使用系统调用(比如 `brk` 或 `mmap`)来向操作系统申请内存。内存管理采用层级架构,分别是线程缓存(`tcache`)、分配区(`arena`)和系统内存(`system memory`),不同大小的内存块对应不同的分配区。 79 | 80 | 每个线程对应一个`tcache`,`tcache`负责当前线程所使用内存块的申请和释放,避免线程间锁的竞争和同步。`tcache`是对`arena`中内存块的缓存,当没有`tcache`时则使用`arena`分配内存。`arena`采用内存池思想对内存区域进行了合理划分和管理,在有效保证低碎片的前提下实现了不同大小内存块的高效管理。 81 | 82 | 当`arena`中有不能分配的超大内存时,再直接使用`mmap`从系统内存中申请,并使用红黑树进行管理。 83 | 84 | 从性能角度考虑,能放在栈上的数据最好不要放在堆上。因此,**Rust的类型默认都是放在栈上**。 85 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/access_to_non-owned_memory.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/access_to_non-owned_memory.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/am.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/am.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/application_memory.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/application_memory.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/array.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/array.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/borrowed_state.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/borrowed_state.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/closures.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/closures.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/dst.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/dst.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/empty_struct.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/empty_struct.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/enum.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/enum.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/f32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/f32.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/function_boundaries.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/function_boundaries.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/function_parameters.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/function_parameters.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/general_purpose_heap_storage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/general_purpose_heap_storage.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/lifetime_of_things.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/lifetime_of_things.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/lifetimes_propagate_borrowed_state.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/lifetimes_propagate_borrowed_state.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/meaning_of_r.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/meaning_of_r.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/moves.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/moves.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/mutex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/mutex.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/nested_functions.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/nested_functions.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/numeric_types.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/numeric_types.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/owned_strigns.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/owned_strigns.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/owned_strings.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/owned_strings.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/pointer_meta.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/pointer_meta.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/problem_of_borrowed_propagation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/problem_of_borrowed_propagation.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/raw_pointers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/raw_pointers.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/rc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/rc.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/references_as_pointers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/references_as_pointers.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/references_pointers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/references_pointers.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/repurposing_memory.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/repurposing_memory.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/scope_drop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/scope_drop.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/sized.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/sized.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/slice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/slice.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/standard_library_types.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/standard_library_types.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/struct.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/struct.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/textual_types.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/textual_types.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/tuple.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/tuple.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/type_safety.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/type_safety.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/typelinkeness_of_lifetimes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/typelinkeness_of_lifetimes.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/union.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/union.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/unlocking.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/unlocking.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/内部实现_img/variable.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/内部实现_img/variable.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/函数/函数.md: -------------------------------------------------------------------------------- 1 | # 定义 2 | 3 | 使用fn定义函数,参数和返回值须标注类型。 4 | 5 | * 以逗号分隔多个参数 6 | * 以`->`指示返回值类型 7 | * 以元组或`Result`返回多个值 8 | * 支持函数嵌套(nested) 9 | * 支持匿名函数和闭包(closure) 10 | * 不支持重载(overload) 11 | * 不支持变参(以macro实现) 12 | * 不支持默认值(以`Option`实现) 13 | 14 | 可用return提前返回,或以表达式作为结束。 15 | 16 | > 隐式返回最后一个表达式值. 17 | > 18 | > 执行流的最后一行, 不一定是函数代码的最后一行. 19 | > 20 | > 即便没有返回值定义,也隐式返回unit. 21 | 22 | ```rust 23 | fn add(x: i64, y: i64) -> i64 { 24 | if x < 0 { 25 | return -1; 26 | } 27 | 28 | let z = x + y; 29 | z // 不能以分号结束,那就成了语句 30 | } 31 | 32 | fn main() { 33 | println!("{}", add(1, 2)); 34 | } 35 | ``` 36 | 37 | 函数是第一类(first-class)对象。可赋值,或作为参数或返回值。 38 | 39 | ```rust 40 | fn add(x: i32, y: i32) -> i32 { 41 | x + y 42 | } 43 | 44 | fn main() { 45 | let f: fn(i32, i32) -> i32; 46 | f = add; 47 | 48 | println!("{:?}", f(1, 2)); 49 | } 50 | ``` 51 | 52 | 函数嵌套 53 | 54 | ```rust 55 | type F = fn(i32, i32) ->i32; 56 | 57 | fn test() -> F { 58 | fn add(x: i32, y: i32) -> i32 { 59 | x + y 60 | } 61 | 62 | return add; 63 | } 64 | 65 | fn main() { 66 | let add = test(); 67 | println!("{:?}", add(1, 2)); 68 | } 69 | ``` 70 | 71 |   72 | 73 | ### 参数默认值 74 | 75 | 利用`Option`实现参数默认值。 76 | 77 | ```rust 78 | fn inc(x: Option) -> i32{ 79 | let a = match x { 80 | Some(v) => v, // x参数传值, 则返回实参值 81 | None => 100, // 默认参数 82 | }; 83 | 84 | a+1 85 | } 86 | 87 | fn main() { 88 | println!("{}", inc(Some(123))); 89 | println!("{}", inc(None)); 90 | } 91 | ``` 92 | 93 | ```rust 94 | fn inc(x: Option) -> i32 { 95 | 96 | // 简略方式 97 | let a = x.unwrap_or(100); 98 | 99 | a + 1 100 | } 101 | ``` 102 | 103 | ```rust 104 | fn inc(x: Option) -> i32 { 105 | if let Some(a) = x { 106 | return x + 1 107 | } 108 | 109 | 101 // 默认值 110 | } 111 | ``` 112 | 113 | ### 多返回值 114 | 115 | 以元组打包需要返回多个值。 116 | 117 | ```rust 118 | fn test() -> (i32, f32) { 119 | (1, 1.2f32) 120 | } 121 | 122 | fn main() { 123 | let (i, f) = test(); // 解构多返回值 124 | 125 | println!("{:?}, {:?}", i, f); 126 | } 127 | ``` 128 | 129 | 还可以用 Result 实现类似 Golang `(result, error)` 返回值。 130 | 131 | ```rust 132 | fn test(x: i32) -> Result { 133 | match x { 134 | x if x > 0 => Ok(1), 135 | _ => Err("error"), 136 | } 137 | } 138 | 139 | fn main() { 140 | let r = test(-1); 141 | match r { 142 | Ok(v) => println!("ok: {:?}", v), 143 | Err(e) => println!("err: {:?}", e), 144 | } 145 | } 146 | ``` 147 | 148 |   149 | 150 | ### 嵌套函数 151 | 152 | 嵌套函数无法使用外层变量。嵌套函数更多的是用于逻辑拆分,而匿名函数和闭包更多是有状态的函数。 153 | 154 | > 需使用匿名函数,才能实现闭包。 155 | 156 | ```rust 157 | fn main() { 158 | let x = 0x64; 159 | 160 | fn test() { 161 | println!("{:?}", x); 162 | ^ can't capture dynamic environment in a fn item 163 | } 164 | 165 | test(); 166 | } 167 | ``` 168 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/函数/闭包/base.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/函数/闭包/base.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/包/包/包.md: -------------------------------------------------------------------------------- 1 | # 包 2 | 3 | **箱子**(crate)对应可执行或库项目;**包**(package)则管理一到多个箱子。 4 | 5 | **规则:** 6 | 7 | * 最少有一个箱子。 8 | * 最多只能有一个library箱子。 9 | * 可以有任意个binary箱子。 10 | 11 | ```bash 12 | $> cargo new my --lib 13 | Created library `my` package 14 | 15 | $> tree my 16 | my 17 | |-- Cargo.toml 18 | `-- src 19 | `-- lib.rs 20 | 21 | 1 directory, 2 files 22 | ``` 23 | 24 |   25 | 26 | > 可选择 `--bin`、`--lib`模版,或在已有目录执行 `init` 命令。 27 | > 28 | > 某些名字(如`test`)有特定意义,不能作为包名。 29 | 30 | ```toml 31 | [package] 32 | name = "demo" 33 | version = "0.1.0" 34 | authors = [] 35 | edition = "2018" 36 | 37 | [dependencies] 38 | byteorder = "0.4.0" 39 | num = "0.1.27" 40 | 41 | [profile.release] 42 | panic = "abort" 43 | 44 | ``` 45 | 46 | [The Manifest Format](https://doc.rust-lang.org/cargo/reference/manifest.html) 47 | 48 |   49 | 50 | ## 编译配置 51 | 52 | 通过配置指定编译参数,分别为: 53 | 54 | * `profile.dev`: `cargo run, build` 55 | * `profile.release`: `cargo build --release` 56 | * `profile.test`: `cargo test` 57 | * `profile.bench`: `cargo bench` 58 | 59 | [Cargo Profiles](https://doc.rust-lang.org/cargo/reference/profiles.html) 60 | 61 |   62 | 63 | ## 依赖管理 64 | 65 | 如果引入第三方包,需要`dependencies`添加依赖设置。 66 | 67 |   68 | 69 | > 相关工具会自动下载并缓存到`~/.cargo/registry`目录下。 70 | > 71 | > 首次构建时,`Cargo.lock`记录依赖信息。至于在修改依赖版本,或运行`cargo update`时才更新。 72 | 73 | 无需再做额外声明,直接以use语句引入成员。 74 | 75 | ```toml 76 | # Cargo.toml 77 | 78 | [dependencies] 79 | futures = "0.3" 80 | ``` 81 | 82 | ```rust 83 | // main.rs 84 | 85 | use futures::executor::block_on; 86 | 87 | async fn hello() { 88 | println!("hello, world"); 89 | } 90 | 91 | fn main() { 92 | block_on(hello()); 93 | } 94 | ``` 95 | 96 |   97 | 98 | ## 版本兼容性规则 99 | 100 | * `0.0`: 不与任何版本兼容。 101 | * `0.x`: 与`0.x`兼容。(0.61 -> 0.63) 102 | * `1.0`: 主版本号保持兼容。(2.01 -> 2.99, not 3.0) 103 | 104 | ```toml 105 | image = "=0.10.0" 106 | image = ">=1.0.5" 107 | image = ">1.0.5 <1.1.9" 108 | image = "<=2.7.10" 109 | ``` 110 | 111 |   112 | 113 | ## 自定义下载路径 114 | 115 | 非cragtes.io包,可手工指定路径。 116 | 117 | ```toml 118 | image = { git = "https://github.com/Piston/image.git", branch = "master" } 119 | iamge = { git = "https://github.com/Piston/image.git", rev = "528f19c" } 120 | iamge = { path = "./vendor/image" } 121 | ``` 122 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/包/导入.md: -------------------------------------------------------------------------------- 1 | # 导入 2 | 3 | 我们可以在模块中以嵌套的方式导入(import)元素,这有助于减少导入操作的资源占用。 4 | 5 | ```rust 6 | use std::sync::{Mutex, Arc, mpsc::channel}; 7 | use std::thread; 8 | 9 | fn main() { 10 | let (tx, rx) = channel(); 11 | 12 | let join_handle = thread::spawn(move || { 13 | while let Ok(n) = rx.recv() { 14 | println!("Received {}", n); 15 | } 16 | }); 17 | 18 | for i in 0..10 { 19 | tx.send(i).unwrap(); 20 | } 21 | 22 | join_handle.join().unwrap(); 23 | } 24 | ``` 25 | 26 |   27 | 28 | ## use 和 extern crate 的区别 29 | 30 | ### extern crate 31 | 32 | `extern crate foo`:引入外部库,要想使其生效,还必须在 `Cargo.toml` 的 `dependecies` 段,加上 `xxx="version num"` 这种依赖说明。引入后,相当于一个符号 `xxx`(`use xxx`),后面直接可以以这个 `xxx` 为根引用这个crate中的item。 33 | 34 | ```rust 35 | extern crate xxx; 36 | 37 | use xxx::yyy::zzz; 38 | ``` 39 | 40 | 从Rust 2018开始,在大多数情况下 `extern crate` 不需要了,直接使用 `use crate` 即可。[use paths](https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html#use-paths) 41 | 42 |   43 | 44 | ### use crate 45 | 46 | 从Rust 2018后, 基本上不再使用 `extern crate`,而是使用 `use crate` 引入外部包。使用 `use` 前,只需要向 `Cargo.toml` 添加外部依赖项即可。 47 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/包/工作空间/工作空间.md: -------------------------------------------------------------------------------- 1 | # 工作空间 2 | 3 | 包除自己的 Cargo.toml 外, 还可通过工作空间(workspace)共享设置。 4 | 5 | ```bash 6 | ; 换成你需要的名字。 7 | $ mykdir workspace 8 | $ cd workspace 9 | 10 | ; 创建多个包。 11 | $ cargo new mylib --lib 12 | $ cargo new my 13 | 14 | ; 创建工作空间配置,添加包成员。 15 | $ cat > Cargo.toml << end 16 | [workspace] 17 | members = ["mylib", "my"] 18 | end 19 | 20 | ; 编译所有包。 21 | $ cargo b --all 22 | Compiling mylib v0.1.0 23 | Compiling my v0.1.0 24 | Finished dev [unoptimized + debuginfo] target(s) in 7.44s 25 | ``` 26 | 27 | ```toml 28 | # workspace/Cargo.toml 29 | 30 | [workspace] 31 | members = ["mylib", "my"] 32 | ``` 33 | 34 | ```bash 35 | $ tree 36 | . 37 | ├── Cargo.toml 38 | ├── my 39 | │ ├── Cargo.toml 40 | │ └── src 41 | │ └── main.rs 42 | └── mylib 43 | ├── Cargo.toml 44 | └── src 45 | └── lib.rs 46 | ``` 47 | 48 |   49 | 50 | 用代码测试一下。 51 | 52 | ```rust 53 | // mylib/src/lib.rs 54 | 55 | pub fn hello() { 56 | println!("hello, world!"); 57 | } 58 | ``` 59 | 60 | ```rust 61 | // my/src/main.rs 62 | 63 | use mylib; 64 | 65 | fn main() { 66 | mylib::hello(); 67 | } 68 | ``` 69 | 70 |   71 | 72 | 在my配置里添加依赖。 73 | 74 | ```toml 75 | # my/Cargo.toml 76 | 77 | [dependencies] 78 | mylib = { path = "../mylib" } 79 | ``` 80 | 81 |   82 | 83 | 编译, 运行! 84 | 85 | * 相关命令直接在工作空间目录执行。 86 | * 生成的文件在工作空间target目录。 87 | 88 | ```bash 89 | $ cargo clean 90 | 91 | $ cargo b --all 92 | Compiling mylib v0.1.0 93 | Compiling my v0.1.0 94 | Finished dev [unoptimized + debuginfo] target(s) in 7.22s 95 | 96 | $ cargo r 97 | Finished dev [unoptimized + debuginfo] target(s) in 0.11s 98 | Running `target/debug/my` 99 | hello, world! 100 | ``` 101 | 102 |   103 | 104 | ## 组织结构示意图 105 | 106 | ```bash 107 | 108 | +===========+ 109 | | workspace | 工程管理(多项目) 110 | +===========+ 111 | | 112 | | +=========+ 113 | +----- | package | 项目管理(依赖、构建) 114 | | +=========+ 115 | | | 116 | +-- .. | +=======+ 117 | | +------ | crate | 项目(库,源文件组织) 118 | | | +=======+ 119 | | | 120 | +-- .. | +========+ 121 | | +----- | module | 模块(代码组织) 122 | | | +========+ 123 | | 124 | +-- .. 125 | | 126 | 127 | ``` 128 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/包/模块/模块.md: -------------------------------------------------------------------------------- 1 | # 模块 2 | 3 | **模块**(module)是命名空间(namespace),是函数、类型、常量的容器,用来组织和隔离代码。模块可以是一个目录、一个源文件,或者单个文件内嵌套。 4 | 5 | * 根文件模块名为`crate`。 6 | * 其他模块以`crate`为起点,按目录层次构成模块树。 7 | 8 | * 子模块,用于分组,控制访问权限。 9 | * 默认私有,添加 `pub` 关键字公开。 10 | 11 | * 父模块不能访问子模块私有成员,反之可行。 12 | * 同级模块,不能访问其私有成员。 13 | * 同一模块,成员互相公开。 14 | 15 | ```rust 16 | mod compiler { 17 | pub mod checker { 18 | pub fn check() { 19 | println!("check!"); 20 | } 21 | } 22 | 23 | pub mod builder { 24 | pub fn build() { 25 | println!("builder!"); 26 | } 27 | 28 | pub fn test() { 29 | super::checker::check(); // 相对路径: 父级 30 | self::build(); // 相对路径: 同级 31 | } 32 | } 33 | } 34 | 35 | fn main() { 36 | crate::compiler::builder::test(); // 绝对路径 37 | } 38 | ``` 39 | 40 | ## 名字引入 41 | 42 | 使用 `use` 关键字,将其它模块成员引入当前作用域。 43 | 44 | * `use mod::member`: 引入其他模块成员,类似 `from module import member`。 45 | * `use mod::member as newname`: 重命名。 46 | * `use mod::{member1, member2}`: 多个成员。 47 | * `user mod::*`: 全部。 48 | 49 | ```rust 50 | fn main() { 51 | use crate::compiler::builder::{build, test}; 52 | 53 | build(); 54 | test(); 55 | } 56 | ``` 57 | 58 |   59 | 60 | 组合引入多个成员。 61 | 62 | ```rust 63 | use std::cmp::Ordering; 64 | use std::io; 65 | 66 | use std::{cmp::Ordering, io}; // !!!! 67 | ``` 68 | 69 | ```rust 70 | use std::io; 71 | use std::io::Write; 72 | 73 | use std::io::{self, Write}; 74 | ``` 75 | 76 | 以 `pub use` 引入的名字,可被外部访问。 77 | 78 | ```rust 79 | mod test { 80 | pub use std::mem::size_of_val; 81 | } 82 | 83 | fn main() { 84 | assert_eq!(test::size_of_val(&1), 4); 85 | } 86 | ``` 87 | 88 |   89 | 90 | ## 模块文件 91 | 92 | 可将模块拆分到不同文件。每个源码文件构成一个**同名模块**,而子目录名则构成**嵌套关系**。 93 | 94 | ```bash 95 | $ tree 96 | . 97 | ├── compiler 98 | │ ├── builder.rs 99 | │ └── checker.rs 100 | ├── compiler.rs 101 | └── main.rs 102 | ``` 103 | 104 |   105 | 106 | 将compiler模块分离到独立文件内,并创建同名子目录保存其内部子模块。 107 | 108 | ```rust 109 | // compiler.rs 110 | 111 | /* 112 | mod 相当于 include/import,将子模块包含进来,建立所属关系。 113 | pub 表示对外公开。 114 | */ 115 | 116 | pub mod builder; 117 | pub mod checker; 118 | ``` 119 | 120 | ```rust 121 | // compiler/checker.rs 122 | 123 | pub fn check() { 124 | println!("check!"); 125 | } 126 | ``` 127 | 128 | ```rust 129 | // compiler/builder.rs 130 | 131 | pub fn build() { 132 | println!("builder!"); 133 | } 134 | ``` 135 | 136 |   137 | 138 | 使用时,同样需要引入模块。 139 | 140 | ```rust 141 | // main.rs 142 | 143 | /* 144 | mod <...>; 不能放在语句块内。 145 | use <...>; 将名字引入所在作用域。 146 | */ 147 | 148 | mod compiler; 149 | use compiler::checker::check; 150 | use compiler::builder::build; 151 | 152 | fn main() { 153 | check(); 154 | build(); 155 | } 156 | ``` 157 | 158 | > 2015: `mod lib;` 表示 `./lib.rs` 或 `./lib/mod.rs`,类似 Python `__init__.py`。 159 | > 160 | > 2018: 修改了该方案。 161 | 162 | > 标准库在所有项目内默认可用,且自动引入几十个常用类型和特征,以便于使用。 163 | 164 |   165 | 166 | [2018: Path clarity](https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-clarity.html) -------------------------------------------------------------------------------- /Rust学习笔记_基础/包/箱/箱.md: -------------------------------------------------------------------------------- 1 | # 箱 2 | 3 | **箱子**(crate)是一个编译单元,分为可执行(binary) 和 库(library)两类。相比这个有些标新立异的名字,我们更习惯称之为 **项目** 或 **库**。 4 | 5 | * 以根文件 `main.rs` 或 `lib.rs` 为起点。 6 | * 同时有上述两个根文件,则代表两个共享源文件的箱子。 7 | * 其余可执行根文件,放在 `src/bin` 目录下。 8 | 9 | 示例: 10 | 11 | ```bash 12 | 13 | $ tree my 14 | 15 | my 16 | |-- Cargo.lock 17 | |-- Cargo.toml 18 | `-- src 19 | |-- bin 20 | | |-- abc.rs 21 | | `-- demo.rs 22 | |-- lib.rs 23 | `-- main.rs 24 | 25 | ``` 26 | 27 | ```toml 28 | # Cargo.toml 29 | 30 | [package] 31 | name = "my" 32 | version = "0.1.0" 33 | authors = [] 34 | edition = "2018" 35 | default-run = "my" 36 | 37 | [dependencies] 38 | ``` 39 | 40 |   41 | 42 | 两个根文件,分别代表 `binary` 和 `library` 箱子。 43 | 44 | ```rust 45 | // lib.rs 46 | 47 | pub fn hello() { 48 | println!("hello, world!"); 49 | } 50 | 51 | pub fn test(s: &str) { 52 | println!("lib: {:?}", s); 53 | } 54 | ``` 55 | 56 | ```rust 57 | // main.rs 58 | 59 | // 不能用 crate::hello。 60 | // crate 代表 main.rs。 61 | 62 | use my::hello; 63 | 64 | fn main() { 65 | hello(); 66 | } 67 | ``` 68 | 69 | 其它 library箱子。 70 | 71 | ```rust 72 | // bin/demo.rs 73 | 74 | use my::test; 75 | 76 | fn main() { 77 | test("src/bin/demo"); 78 | } 79 | ``` 80 | 81 | ```rust 82 | // bin/abc.rs 83 | 84 | use my::test; 85 | 86 | fn main() { 87 | test("src/bin/abc"); 88 | } 89 | ``` 90 | 91 |   92 | 93 | 编译: 94 | 95 | ```rust 96 | Compiling my v0.1.0 (/root/rs/my) 97 | Running `rustc --crate-name my src/lib.rs --crate-type lib 98 | Running `rustc --crate-name demo src/bin/demo.rs --crate-type bin 99 | Running `rustc --crate-name abc src/bin/abc.rs --crate-type bin 100 | Running `rustc --crate-name my src/main.rs --crate-type bin 101 | 102 | Finished dev [unoptimized + debuginfo] target(s) in 4.47s 103 | ``` 104 | 105 |   106 | 107 | [Cargo Targets](https://doc.rust-lang.org/cargo/reference/cargo-targets.html) -------------------------------------------------------------------------------- /Rust学习笔记_基础/宏和元编程/元编程.md: -------------------------------------------------------------------------------- 1 | # 元编程 2 | 3 | 元编程(Metaprogramming)是指某类计算机程序的编写,这类计算机程序编写或者操作其它程序(或者自身)作为它们的数据,或者在运行时完成部分本应在编译时完成的工作。很多情况下与手工编写全部代码相比工作效率更高,编写元程序的语言称之为元语言,被操作的语言称之为目标语言。一门语言同时也是自身的元语言的能力称之为反射。 4 | 5 |   6 | 7 | ## 元编程的概念 8 | 9 | 元编程是一种编程技术,你可以编写能够生产新代码的代码。根据语言的不同,实现的方式有两种: 10 | 11 | * **运行时**: 运行时元编程可用于动态语言,例如Python、Javascript及Lisp。 12 | * **编译期**: 编译型语言不可能在运行时生成指令,因为这些语言会执行程序**预编译**。但是你可以选择在编译期生成代码,这是C宏提供的代码。Rust还提供编译期生成功能,它们比C宏的功能更强大、更健壮。 13 | 14 | 反射是促进元编程的一种很有价值的语言特性。把编程语言自身作为头等对象(Lisp或Rebol)也很有用。支持泛型编程的语言也使用元编程能力。 15 | 16 | 元编程通常有两种方式起作用: 17 | 18 | * 通过API来暴露运行时引擎的内部信息。 19 | * 动态执行包含编程命令的字符串。 20 | 21 |   22 | 23 | ## 元编程_宏 24 | 25 | 很多语言中,元编程构造通常会用宏表示。通常,宏将任意代码序列作为输入,并输出可由语言编译或执行的有效代码和其他代码。 26 | 27 | 宏的输入不需要是有效的语法,你可以自由地为宏输入定义的语法。此外,调用宏的方式和定义它们的语法也因语言而异。 28 | 29 | ```rust 30 | macro_rules! switch { 31 | ($a: expr, $b: expr) => { 32 | temp = $b; $b = $a; $a = temp; 33 | }; 34 | } 35 | 36 | fn main() { 37 | let x = 1; 38 | let y = 2; 39 | let temp = 3; 40 | switch!(x, y); 41 | } 42 | ``` 43 | 44 |   45 | 46 | 如上代码 `switch!`宏对在 `main` 函数中声明的 `temp` 变量一无所知。Rust宏不会从执行环境中捕获变量,因为它与C 宏的工作方式不同。即使它会,我们也将在修改处保存,因为程序中声明的 `temp` 是不可变的。 47 | 48 | ```rust 49 | $ cargo expand 50 | 51 | // 预编译; 宏展开 52 | #![feature(prelude_import)] 53 | #[prelude_import] 54 | use std::prelude::rust_2018::*; 55 | #[macro_use] 56 | extern crate std; 57 | fn main() { 58 | let x = 1; 59 | let y = 2; 60 | let temp = 3; 61 | temp = y; 62 | y = x; 63 | x = temp; 64 | } 65 | ``` 66 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/对象/复制/复制.md: -------------------------------------------------------------------------------- 1 | # 复制 2 | 3 | 实现`Copy`特征,以复制代替所有权转移。复制是隐式发生的,例如作为赋值`y=x`的一部分,`Copy`的行为不可重载,复制总是按位复制。 4 | 5 | > 因为`Clone`是`Copy`的`SuperTrait`,所以总是成对出现。 6 | 7 | ```rust 8 | 9 | #[derive(Debug)] 10 | struct Data {} 11 | 12 | fn main() { 13 | let a = Data{}; 14 | let b = a; // move!!! 15 | 16 | println!("{:?}", a); 17 | // ^ value borrowed here after move 18 | } 19 | ``` 20 | 21 | ```rust 22 | #[derive(Debug, Copy, Clone)] 23 | struct Data{} 24 | 25 | fn main() { 26 | let a = Data{}; 27 | let b = a; // Copy!!! 28 | 29 | println!("{:?}", a); 30 | } 31 | ``` 32 | 33 |   34 | 35 | ## Copy使用场景 36 | 37 | 1. 不适合使用 `Copy` 场景: 38 | - `&mut T` 39 | - `string` 40 | - 实现`Drop`的类型不能使用`Copy` 41 | 42 | 2. 适合使用 `Copy` 场景: 43 | - 一个类型的所有属性(组建)都实现了 `Copy`,那么它就可以实现 `Copy` 44 | - 共享引用(`&T`)也是 `Copy`,所以该类型也可以实现 `Copy` 45 | 46 |   47 | 48 | 以下类型可以实现 `Copy`: 49 | 50 | ```rust 51 | // 一个类型所有属性都实现了Copy 52 | 53 | #[derive(Copy, Clone)] 54 | struct Point { 55 | x: i32, 56 | y: i32, 57 | } 58 | 59 | // 共享引用(`&T`)也是 `Copy`,所以该类型也可以实现 `Copy` 60 | 61 | struct PointList; 62 | 63 | #[derive(Copy, Clone)] 64 | struct PointListWrapper<'a> { 65 | point_list_ref: &'a PointList, 66 | } 67 | ``` 68 | 69 |   70 | 71 | 以下类型不可以实现 `Copy`: 72 | 73 | ```rust 74 | struct Point; 75 | 76 | struct PointList { 77 | points: Vec, 78 | } 79 | ``` 80 | 81 |   82 | 83 | ## 实现Copy方法 84 | 85 | 有两种方法实现`Copy`的方法。 86 | 87 | 1. 使用`derive` 88 | 89 | ```rust 90 | #[derive(Copy, Clone)] 91 | struct MyStruct; 92 | ``` 93 | 94 | 2. 手工实现`Copy`和`Clone` 95 | 96 | ```rust 97 | struct MyStruct; 98 | 99 | impl Copy for MyStruct{ } 100 | 101 | impl Clone for MyStruct { 102 | fn clone(&self) -> MyStruct { 103 | *self 104 | } 105 | } 106 | ``` 107 | 108 |   109 | 110 | ## Copy和Clone的区别 111 | 112 | ### Copy 113 | 114 | `Copy`是隐式发生的,例如,作为赋值`y=x`的一部分,`Copy`的行为不可重载,复制总是按位复制。 115 | 116 | ### Clone 117 | 118 | `Clone`是一个显式操作,`x.clone()`。`Clone`的实现可以提供安全复制值所需的任何特定于类型的行为。 例如, `String`类型的`Clone`实现需要将指向的**字符串缓冲区**复制到heap。 119 | 120 | `String`值的简单按位复制,只会复制指针,从而导致重复释放。因此,`String`是`Clone`而不是`Copy`。 121 | 122 | `Clone`是 `Copy`的 `SuperTrait`, 所以它们总是成对出现。如果一个类型是`Copy`,那么它的`Clone`只需要返回`*self`即可。 123 | 124 |   125 | 126 | ## Copy位复制问题 127 | 128 | 位复制有些问题,比如字符串(String),它分头部结构和堆上字符数组两部分。如果只复制头,那么就可能造成堆数据多次释放。因此,我们可以实现Clone特征,自定义克隆操作。 129 | 130 | 相比 `Copy` 的隐式行为,`Clone` 总是显式调用。另外,`Copy` 不会调用 `Clone`方法。 131 | 132 | ```rust 133 | #[derive(Debug)] 134 | struct Data { 135 | x: i32, 136 | y: i32, 137 | } 138 | 139 | impl Copy for Data{} 140 | 141 | impl Clone for Data { 142 | fn clone(&self) -> Self { 143 | Self { x: self.x, y: 0 } 144 | } 145 | } 146 | 147 | /* ------------------------------ */ 148 | fn main() { 149 | let a = Data{ x: 10, y: 20 }; 150 | let b = a.clone(); // 显式复制 151 | 152 | assert_eq!(b.x, 10); 153 | assert_eq!(b.y, 0); 154 | } 155 | ``` 156 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/对象/析构/析构.md: -------------------------------------------------------------------------------- 1 | # 析构 2 | 3 | 通过实现`Drop`特征来自定义析构函数(destructor)。超出作用域时,析构函数被自动调用。 4 | 5 | ```rust 6 | struct Data{} 7 | 8 | impl Drop for Data { 9 | fn drop(&mut self) { 10 | println!("drop!"); 11 | } 12 | } 13 | 14 | /* ------------------------ */ 15 | 16 | fn main() { 17 | { 18 | let _d = Data{}; 19 | } 20 | 21 | println!("exit"); 22 | } 23 | ``` 24 | 25 | 通常无需定义析构函数,编译器会自动生成 **胶水函数** (drop glue) 递归释放所有字段成员。即便自定义了析构函数,也无需手工释放字段成员。可专注于关闭文件和网络套接字等清理任务。 26 | 27 |   28 | 29 | > 结构按字段定义顺序释放,而本地变量则按定义反向顺序释放。 30 | > 31 | > 实际上,我们的逻辑不应该依赖这种顺序。 32 | 33 |   34 | 35 | ```rust 36 | 37 | struct Data {} 38 | 39 | impl Drop for Data { 40 | fn drop(&mut self) { 41 | println!("drop!"); 42 | } 43 | } 44 | 45 | /* -------------------------- */ 46 | 47 | struct Demo { 48 | d: Data, 49 | b: Box, 50 | s: String 51 | } 52 | 53 | /* --------------------------- */ 54 | 55 | fn main() { 56 | { 57 | let _d = Demo { 58 | d: Data{}, 59 | b: Box::new(100), 60 | s: String::from("abc"), 61 | }; 62 | } 63 | 64 | println!("exit"); 65 | } 66 | ``` 67 | 68 | ```x86asm 69 | (gdb) disass 70 | Dump of assembler code for function demo::main: 71 | 72 | call 0x55555555afe0 > 73 | 74 | End of assembler dump. 75 | 76 | 77 | (gdb) disass 0x55555555afe0 78 | Dump of assembler code for function drop_in_place: 79 | 80 | call 0x55555555afc0 > 81 | call 0x55555555b0d0 >> 82 | call 0x55555555b060 > 83 | 84 | End of assembler dump. 85 | ``` 86 | 87 |   88 | 89 | 不允许直接调用析构函数,以 `drop` 函数代替。 90 | 91 | > 该函数实质就是个空函数,通过参数转移所有权来表达释放目的。也因此对实现了 `Copy` 特征的对象无效。 92 | 93 | ```rust 94 | 95 | d.drop(); 96 | ^^^ explicit destructor calls not allowed 97 | ``` 98 | 99 | ```rust 100 | struct Data {} 101 | 102 | impl Drop for Data { 103 | fn drop(&mut self) { println!("drop!"); } 104 | } 105 | 106 | /* ---------------------------------------- */ 107 | 108 | struct Demo { 109 | d: Data, 110 | b: Box, 111 | s: String 112 | } 113 | 114 | /* ---------------------------------------- */ 115 | 116 | fn main() { 117 | let d = Demo{ 118 | d: Data{}, 119 | b: Box::new(100), 120 | s: String::from("abc"), 121 | }; 122 | 123 | std::mem::drop(d); 124 | 125 | 126 | 127 | println!("exit"); 128 | } 129 | ``` 130 | 131 | ```x86asm 132 | (gdb) disassemble 133 | 134 | 0x000055555555a045 <+181>: call 0x55555555a100 135 | 136 | 137 | (gdb) disassemble 0x55555555a100 138 | Dump of assembler code for function core::mem::drop: 139 | 0x000055555555a100 <+0>: push rax 140 | 0x000055555555a101 <+1>: call 0x555555559350 141 | 0x000055555555a106 <+6>: pop rax 142 | 0x000055555555a107 <+7>: ret 143 | End of assembler dump. 144 | ``` 145 | 146 | **不能同时为一个目标实现 Copy 和 Drop, 它们是独占的。** -------------------------------------------------------------------------------- /Rust学习笔记_基础/对象/泛型/phantomType.md: -------------------------------------------------------------------------------- 1 | # phantom type 2 | 3 | 虚类型(phantom type) 参数是一种在运行时不出现,仅在编译时进行静态检查的类型参数。 4 | 5 | 可以用额外的泛型类型参数指定数据类型,该类型可以充当标记,也可以供编译时类型检查使用。这些额外的参数没有存储值,也没有运行时行为。 6 | 7 | ```rust 8 | use std::marker::PhantomData; 9 | 10 | // 该虚元组结构体对 `A` 是泛型的,并且带有隐藏参数 `B` 11 | struct PhantomTuple(A, PhantomDta); 12 | 13 | // 该虚元组结构体对 `A` 是泛型的,并且带有隐藏参数 `B` 14 | struct PhantomStruct{ first: A, phantom: PhantomData} 15 | ``` 16 | 17 | 对于泛型 `A` 会分配存储空间,但 `B` 不会。因此,`B` 不能参与运算。 18 | 19 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/对象/特征/传递/传递.md: -------------------------------------------------------------------------------- 1 | # 传递 2 | 3 | 将特征作为`参数`和`返回值`类型。 4 | 5 | ```Rust 6 | trait TestTrait { 7 | fn test(&self) { 8 | println!("test"); 9 | } 10 | } 11 | 12 | impl TestTrait for i32 {} 13 | 14 | /* ------------------------------------------- */ 15 | 16 | fn test(x: impl TestTrait) -> impl TestTrait { 17 | x.test(); 18 | x 19 | } 20 | 21 | fn main() { 22 | let t = test(123); 23 | t.test(); 24 | } 25 | ``` 26 | 27 |   28 | 29 | 泛型版本。 30 | 31 | ```Rust 32 | fn test(x: &T) -> &T where T: TestTrait{ 33 | x.test(); 34 | x 35 | } 36 | 37 | fn main() { 38 | let t = test(&123); 39 | t.test(); 40 | } 41 | ``` 42 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/对象/特征/关联/关联.md: -------------------------------------------------------------------------------- 1 | # 关联 2 | 3 | 定义特征时,可用**关联类型**(associated type)设定延迟类型。因此,也被称作**类型占位符号**。 4 | 5 | ```rust 6 | use std::default::Default; 7 | 8 | trait TestTrait { 9 | type A: Default; // <------- 用别名和约束,先用起来 10 | 11 | fn get_default(&self) -> Self::A { 12 | Default::default() 13 | } 14 | } 15 | 16 | /* -------------------------------- */ 17 | 18 | impl TestTrait for i32 { 19 | type A = i32; // <-------- 把别名补上 20 | } 21 | 22 | /* --------------------------------- */ 23 | fn main() { 24 | assert_eq!(1.get_default(), 0); 25 | } 26 | ``` 27 | 28 |   29 | 30 | 作为参数时,须指定关联类型。 31 | 32 | ```rust 33 | fn test(x: &dyn TestTrait) { // 光有别名是没法用的 34 | assert_eq!(x.get_default(), 0); 35 | } 36 | 37 | fn main() { 38 | test(&1); 39 | } 40 | ``` 41 | 42 |   43 | 44 | **关联类型** 和 **泛型**都可以为特征提供额外的**延迟类型**用于装配。两者最大的区别在于, **泛型可以为单个目标实现多个不同特征,而关联类型只能有一个**。 45 | 46 | > 泛型: 同一个模板生产的进口版和合资汽车,似是而非 47 | > 48 | > 关联: 同一辆车,改装不同的发动机。 49 | 50 | ```rust 51 | impl TestTrait for Data 52 | impl TestTrait for Data 53 | ``` 54 | 55 | ```rust 56 | impl TestTrait for Data { 57 | type X = i32; 58 | } 59 | ``` -------------------------------------------------------------------------------- /Rust学习笔记_基础/对象/特征/其它.md: -------------------------------------------------------------------------------- 1 | # 其它 2 | 3 | 特征相关知识补充,及使用技巧。 4 | 5 | ## 注释 6 | 7 | 编译器允许以注解语法(`#[derive]`)为类型自动实现某些特征。 8 | 9 | * `Clone`: 从`&T`创建副本`T`。 10 | * `Copy`: 自动调用, 以复制代替所有权转移。 11 | * `Debug`: 使用`{:?}`格式化。 12 | * `Default`: 创建默认实例。 13 | * `Eq`, `PartialEq`, `Ord`, `PartialOrd`: 比较。 14 | * `Hash`: 计算哈希值。 15 | 16 |   17 | 18 | ```rust 19 | #[derive(Debug, Copy, Clone)] 20 | struct Data{} 21 | ``` 22 | 23 | ## 孤儿规则 24 | 25 | 实现特征时,类型或特征至少有一个是在当前`create`内定义。无法为外部类型实现外部特征。 26 | 27 | ```rust 28 | 29 | trait ToInt { 30 | fn to_int32(&self) -> i32 { 31 | 100 32 | } 33 | } 34 | 35 | impl ToInt for &str {} 36 | 37 | /* -------------------------------- */ 38 | 39 | fn main() { 40 | let s = "abc"; 41 | assert_eq!(s.to_int32(), 100); 42 | } 43 | ``` 44 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/对象/特征/同名/同名.md: -------------------------------------------------------------------------------- 1 | # 同名 2 | 3 | 即便目标类型已经有同名成员,依旧要再次实现。多个特征(trait)的同名方法,同样须独立实现。 4 | 5 | 特征(trait)的独立实现方式,有点儿像混入(mixins)。在不改变原类型的情况下,为其添加外挂。这样做其它好处就是各自分组维护,不会让代码变得臃肿。 6 | 7 | 当然,作为拿到`Self`和`self`参数的外挂,调用原类型成员是没啥问题的。 8 | 9 |   10 | 11 | ```rust 12 | struct Data{} 13 | 14 | impl Data { 15 | fn test(&self) -> &'static str { 16 | "method" 17 | } 18 | } 19 | 20 | /* -------------------------------------- */ 21 | 22 | trait A { 23 | fn test(&self) -> &'static str; 24 | } 25 | 26 | impl A for Data { 27 | fn test(&self) -> &'static str { 28 | "A" 29 | } 30 | } 31 | 32 | /* ---------------------------------------- */ 33 | 34 | trait B { 35 | fn test(&self) -> &'static str; 36 | } 37 | 38 | impl B for Data { 39 | fn test(&self) -> &'static str { 40 | "B" 41 | } 42 | } 43 | 44 | /* ------------------------------------------- */ 45 | 46 | fn main() { 47 | let d = Data{}; 48 | assert_eq!(d.test(), "method"); // 默认 49 | 50 | assert_eq!(A::test(&d), "A"); 51 | assert_eq!(::test(&d), "A"); // 完全限定语法; 使用Data的A的实现 52 | } 53 | ``` 54 | 55 | ```x86asm 56 | (gdb) disassemble 57 | Dump of assembler code for function ddd::Data::test: 58 | 0x00005555555593b0 <+0>: push rax 59 | 0x00005555555593b1 <+1>: mov QWORD PTR [rsp],rdi 60 | 0x00005555555593b5 <+5>: lea rax,[rip+0x31c44] # 0x55555558b000 61 | => 0x00005555555593bc <+12>: mov edx,0x6 62 | 0x00005555555593c1 <+17>: pop rcx 63 | 0x00005555555593c2 <+18>: ret 64 | End of assembler dump. 65 | 66 | (gdb) p/x $rax 67 | $1 = 0x55555558b000 68 | 69 | (gdb) x/6xb 0x55555558b000 70 | 0x55555558b000: 0x6d 0x65 0x74 0x68 0x6f 0x64 // 存储具体内容: method 71 | 72 | (gdb) info proc mappings 73 | process 400 74 | Mapped address spaces: 75 | 76 | 0x55555558b000 0x555555597000 0xc000 0x37000 /root/rs/ddd/target/debug/ddd // .rodata 77 | ``` 78 | 79 | > 完全限定语法定义: 80 | > 81 | > \::function(receiver_if_method, next_arg, ...); -------------------------------------------------------------------------------- /Rust学习笔记_基础/对象/特征/泛型/泛型.md: -------------------------------------------------------------------------------- 1 | # 泛型 2 | 3 | 定义通用泛型模版,由此衍生出多个特征。 4 | 5 | ```rust 6 | use std::ops::Add; 7 | 8 | trait Double where 9 | T: Copy + Add // + 操作符约束; Output 关联类型 10 | { 11 | fn to(&self, x: &T) -> T { *x + *x } 12 | } 13 | 14 | /* ------------------------------------------------------ */ 15 | 16 | #[derive(Debug)] 17 | struct Data {} 18 | 19 | impl Double for Data {} // 变向实现重载? 20 | impl Double for Data {} 21 | 22 | /* ------------------------------------------------------ */ 23 | 24 | fn main() { 25 | let d = Data{}; 26 | assert_eq!(d.to(&10), 20); 27 | assert_eq!(d.to(&1.1), 2.2); 28 | } 29 | ``` 30 | 31 |   32 | 33 | 可指定默认类型。 34 | 35 | ```rust 36 | use std::ops::Add; 37 | 38 | trait Double where 39 | T: Copy + Add 40 | { 41 | fn to(&self, x: &T) -> T { 42 | *x + *x 43 | } 44 | } 45 | 46 | /* ------------------------------ */ 47 | 48 | #[derive(Debug)] 49 | struct Data {} 50 | 51 | impl Double for Data {} 52 | 53 | /* ------------------------------- */ 54 | 55 | fn main() { 56 | let d = Data{}; 57 | assert_eq!(d.to(&10), 20); 58 | } 59 | ``` 60 | 61 |   62 | 63 | 当然,还可以组合两套泛型模版,形成一套新模版。 64 | 65 | ```rust 66 | use std::ops::Add; 67 | 68 | trait Double where 69 | T: Copy + Add 70 | { 71 | fn to(&self, x: &T) -> T { 72 | *x + *x 73 | } 74 | } 75 | 76 | /* ---------------------------------- */ 77 | 78 | #[derive(Debug)] 79 | struct Data { x: T } 80 | 81 | impl Double for Data where 82 | T: Copy + Add // Output关联类型,占位; 约束参数T类型 83 | { 84 | 85 | } 86 | 87 | /* ------------------------------------ */ 88 | 89 | fn main() { 90 | let d = Data{ x: 1 }; 91 | assert_eq!(d.to(&10), 20); 92 | 93 | let d = Data{ x:1.1 }; 94 | assert_eq!(d.to(&1.1), 2.2); 95 | } 96 | ``` 97 | 98 | > 注意: 99 | > 100 | > impl Double for Data, 必须在 `impl`后面声明`T`,这样做可以在`Data`上实现的方法中使用它了。在`impl`之后声明泛型`T`,这样Rust就知道`Data`和`Double`的尖括号中的类型是泛型而不是具体类型。 101 | 102 | ### 关联类型(associated types) 103 | 104 | 关联类型(associated tyeps)是一个将类型占位符与`trait`相关联的方式,这样`trait`的方法签名中就可以使用这些占位符类型。`trait`的实现者会针对特定的实现在这个类型的位置指定相应的具体类型。如此可以定义一个使用多种类型的`trait`,直到实现此`trait`时都无需知道这些类型具体是什么。 105 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/对象/特征/特征对象.md: -------------------------------------------------------------------------------- 1 | # 特征对象 2 | 3 | 除了使用静态分发上下文中特征的应用,即在泛型API中设置特征区间。还可以创建多态API的方法,可以将参数指定为实现某个特征的东西,而不是**泛型**或**具体类型**。特征对象实现为胖指针,并且是不定长类型,这意味着它们只能在引用符号(&)后面使用。 4 | 5 |   6 | 7 | > 胖指针: 通常指的是一种指针,它除了存储所指向对象的地址外,还存储一些额外的数据。 8 | 9 |   10 | 11 | 特征对象是Rust执行动态分发的方式: 12 | 13 | * 我们没有实际的具体类型信息。通过跳转到 `vtable` 并调用适当的方法完成方法解析。 14 | * 特征对象的另一个用例,它们允许用户对可以具有多种类型的集合进行操作,但是在运行时需要额外的间接指针引用开销。 15 | 16 | ```rust 17 | use std::fmt::Debug; 18 | 19 | #[derive(Debug)] 20 | struct Square(f32); 21 | 22 | #[derive(Debug)] 23 | struct Rectangle(f32, f32); 24 | 25 | trait Area: Debug { 26 | fn get_area(&self) -> f32; 27 | } 28 | 29 | impl Area for Square { 30 | fn get_area(&self) -> f32 { 31 | self.0 * self.0 32 | } 33 | } 34 | 35 | impl Area for Rectangle { 36 | fn get_area(&self) -> f32 { 37 | self.0 * self.1 38 | } 39 | } 40 | 41 | fn main() { 42 | let shapes: Vec<&dyn Area> = vec![&Square(3f32), &Rectangle(4f32, 2f32)]; 43 | for s in shapes { 44 | println!("{:?}", s); 45 | } 46 | } 47 | ``` 48 | 49 | ```x86asm 50 | // 特征对象类型 51 | (gdb) info locals 52 | shapes = Vec(size=2) = {ddd::&Area { 53 | pointer: 0x555555595000 "\000", 54 | vtable: 0x5555555a4f58 55 | }, ddd::&Area { 56 | pointer: 0x555555595004 "\000", 57 | vtable: 0x5555555a4f80 58 | }} 59 | 60 | // vtable 数据结构 61 | (gdb) x/4xg 0x5555555a4f58 62 | 0x5555555a4f58: 0x000055555555a440 0x0000000000000004 63 | 0x5555555a4f68: 0x0000000000000004 0x000055555555a810 64 | 65 | // vtable destructor 66 | // 析构函数 67 | (gdb) x/xg 0x000055555555a440 68 | 0x55555555a440 : 0x247c894810ec8348 69 | 70 | // 执行方法 71 | (gdb) x/xg 0x000055555555a810 72 | 0x55555555a810 <::get_area>: 0x100ff3243c894850 73 | ``` 74 | 75 | ```rust 76 | // 特征对象数据结构 77 | struct trait_object { 78 | pointer: *mut (), // rdi: lea data (void*) 79 | vtable : *mut (), // rsi: vtable 80 | } 81 | 82 | struct vtable { 83 | destructor: fn(*mut ()), // 析构函数(drop_in_place) 84 | size : usize, // 大小 85 | align : usize, // 内存对齐 86 | method : fn(), // 执行函数 87 | } 88 | ``` 89 | 90 | `shapes` 的元素类型是 `&dyn Area`,特征对象是由 `dyn Area` 表示的,意味着它是指向 `Area`特征某些实现的指针。特征对象形式的类型允许用户在集合类型中存储不同类型。 91 | 92 |   93 | 94 | ## `dyn Trait` 作为函数中的参数使用 95 | 96 | ```rust 97 | use std::fmt::Display; 98 | 99 | fn show_me(item: &dyn Display) { 100 | println!("{ }", item); 101 | } 102 | 103 | fn main() { 104 | show_me(&"Hello trait object"); 105 | } 106 | ``` 107 | 108 |   109 | 110 | 特征和泛型通过 **单态化(早期绑定)** 或 **运行时多态(后期绑定)** 提供了两种代码复用的方式。 何时使用它们取决于具体情况和相关应用程序的需求。 111 | 112 | 通常,错误类型会被分配到**动态分发**的序列,因为它们应该是很少被执行的代码路径。单态化对小型的应用场景来说非常方便,但是缺点是导致了代码的膨胀和重复,这回影响缓存效率,并增加二进制文件的大小。但是,在这两个选项中,**静态分发应该是首选,除非系统对二进制文件大小存在严格的限制。** 113 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/对象/特征/特征对象和对象安全性.md: -------------------------------------------------------------------------------- 1 | # 特征对象和对象安全性 2 | 3 | 自定义类型如果没有 `self` 引用,就无法从中创建特征对象。 4 | 5 | ```rust 6 | trait Foo { 7 | // fn foo(); 8 | // ^^^^ `Foo` cannot be made into an object 9 | 10 | fn foo(self); 11 | } 12 | 13 | fn generic(val: &Foo) { 14 | 15 | } 16 | 17 | fn main() { 18 | 19 | } 20 | ``` 21 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/对象/特征/继承/继承.md: -------------------------------------------------------------------------------- 1 | # 继承 2 | 3 | 特征的继承,和我们以往熟悉的理念有些不同。 4 | 5 |   6 | 7 | ```rust 8 | trait SuperTrait { 9 | fn test(&self); 10 | } 11 | 12 | trait SubTrait: SuperTrait { 13 | fn hello(&self) { 14 | SuperTrait::test(self); // 可调用"基类"方法 15 | } 16 | } 17 | 18 | impl SubTrait for i32 { 19 | fn test(&self) { 20 | println!("{}", self); 21 | } 22 | // ^ error[E0407]: method `test` is not a member of trait `SubTrait` // 没有 ??? 不是继承么 ??? 23 | } 24 | 25 | /* ------------------------------------------------------------------- */ 26 | 27 | fn main() { 28 | 123.test(); 29 | } 30 | ``` 31 | 32 |   33 | 34 | 得单独实现"基类"? 35 | 36 | ```rust 37 | impl SuperTrait for i32 { 38 | fn test(&self) { 39 | println!("{}", self); // 能行。 这还叫继承??? 40 | } 41 | } 42 | 43 | impl SubTrait for i32 {} // 这个不能少 44 | ``` 45 | 46 |   47 | 48 | 实际上,特征继承更像是一种**需求组合**。也就是说,如果**要实现子特征,那么也必须实现父特征**。或者换一个方式,把所谓的**继承改成约束**,这就好理解了。下面的方式完全相同。 49 | 50 | 继承和两个无关特征还是有区别的: 其一,可调用"基类"成员; 其二,强调增补,而非重复实现。 51 | 52 | ```rust 53 | 54 | trait SubTrait where Self: SuperTrait { 55 | fn hello(&self) { 56 | SuperTrait::test(self); 57 | } 58 | } 59 | ``` 60 | 61 |   62 | 63 | 既然两者之间并非传统`OOP`继承关系,自然也就有了选择歧义问题。 64 | 65 | ```rust 66 | trait SuperTrait { 67 | fn test(&self){ 68 | println!("SuperTrait"); 69 | } 70 | } 71 | 72 | trait SubTrait where Self: SuperTrait { 73 | fn test(&self) { 74 | println!("SubTrait"); 75 | } 76 | } 77 | 78 | fn main() { 79 | // 123.test(); 80 | // ^^^^ multiple `test` found 81 | 82 | SuperTrait::test(&123); 83 | SubTrait::test(&123); 84 | } 85 | ``` 86 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/对象/迭代器/迭代器.md: -------------------------------------------------------------------------------- 1 | # 迭代器 2 | 3 | 标准库中的集合类型(std::collections)提供了不同的迭代方式,以供选择。 4 | 5 | * `iter`: `&T`。 6 | * `iter_mut`: `&mut T`。 7 | * `into_iter`: `T`。 8 | 9 | ```rust 10 | fn main() { 11 | let v = vec![10, 11, 12, 13]; 12 | 13 | for e in &v { // v.iter() 14 | println!("{}", e); 15 | } 16 | } 17 | ``` 18 | 19 | ```rust 20 | 21 | fn main() { 22 | let mut v = vec![10, 11, 12, 13]; 23 | 24 | for e in &mut v { // v.iter_mut() 25 | *e += 1; 26 | } 27 | 28 | println!("{:?}", v); 29 | } 30 | ``` 31 | 32 | ```rust 33 | fn main() { 34 | let v = vec![10, 11, 12, 13]; 35 | 36 | for e in v { // v.into_iter() 37 | println!("{}", e); 38 | } 39 | 40 | // println!("{:?}", v); 41 | // ^ value borrowed here after move 42 | } 43 | ``` 44 | 45 |   46 | 47 | ## 适配器 48 | 49 | 适配器(adapter)让我们以链式风格处理迭代器。 50 | 51 | ```rust 52 | fn main() { 53 | let v = vec![10, 11, 12, 13]; 54 | 55 | v.iter() 56 | .take(2) 57 | .map(|x| x+1) 58 | .for_each(|x| println!("{}", x)); 59 | } 60 | ``` 61 | 62 |   63 | 64 | 迭代器是惰性的,如果没有for_each 或 for 循环,那么什么都不会做。 65 | 66 | ```rust 67 | warning: unused `Map` that must be used 68 | --> src/main.rs:8:5 69 | | 70 | 8 | / v.iter() 71 | 9 | | .take(2) 72 | 10 | | .map(|x| x+1); 73 | | |______________________^ 74 | | 75 | = note: `#[warn(unused_must_use)]` on by default 76 | = note: iterators are lazy and do nothing unless consumed 77 | ``` 78 | 79 |   80 | 81 | ## 自定义 82 | 83 | 实现 `Iterator` 特征来实现自己的迭代器。通常独立于实现,避免对原对象状态造成干扰。 84 | 85 | ```rust 86 | // 元组结构 87 | struct Data(Vec); 88 | 89 | impl Data { 90 | 91 | // 返回新的迭代器。 92 | fn iter(&self) -> DataIterator { 93 | DataIterator{ data: self, index: 0 } 94 | } 95 | } 96 | 97 | /* ------------------------------------------------- */ 98 | 99 | // 迭代器 100 | struct DataIterator<'a> { 101 | data : &'a Data, 102 | index: usize, 103 | } 104 | 105 | // 迭代器特征实现 106 | impl Iterator for DataIterator<'_> { 107 | type Item = i32; 108 | 109 | fn next(&mut self) -> Option { 110 | if self.index >= self.data.0.len() { return None } 111 | 112 | let x = self.data.0[self.index]; 113 | self.index += 1; 114 | 115 | Some(x) 116 | } 117 | } 118 | 119 | /* ------------------------------------------------- */ 120 | 121 | fn main() { 122 | let d = Data(vec![1, 2, 3, 4]); 123 | 124 | // 循环 125 | for x in d.iter() { 126 | println!("{:?}", x); 127 | } 128 | 129 | // 适配器 130 | d.iter().for_each(|x| println!("{:?}", x)); 131 | 132 | // 转换 133 | use std::iter::FromIterator; 134 | assert_eq!(Vec::from_iter(d.iter()), [1, 2, 3, 4]); 135 | } 136 | ``` 137 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/工具/环境问题.md: -------------------------------------------------------------------------------- 1 | # 环境问题 2 | 3 | ## gdb调试问题 4 | 5 | Rust在进行调试时,需要依赖 `stdlib` 等库的源文件。所以需要安装 `rust-src` 并设置环境变量,否则 gdb时由于缺少库函数导致无法进行调试。 6 | 7 | ```bash 8 | $> rustup component add rust-src 9 | $> export RUST_SRC_PATH="$(rustc --print sysroot)/lib/rustlib/src/rust/src" 10 | 11 | ## 修改gdb配置文件 12 | 13 | $> touch ~/.gdbinit 14 | set disassembly intel 15 | set print pretty on 16 | set substitute-path '/rustc/f1edd0429582dd29cccacaf50fd134b05593bd9c' '/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust' 17 | ``` 18 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/README.md: -------------------------------------------------------------------------------- 1 | # 并发 2 | 3 | Rust 的并发依赖于本机的操作系统线程,它在标准库中的 `std::thread` 模块中提供了线程API。 4 | 5 |   6 | 7 | ## 访问线程中的数据 8 | 9 | 不与父线程交互的子线程是非常少见的。 10 | 11 | ```rust 12 | 13 | use std::thread; 14 | 15 | fn main() { 16 | let nums = vec![0, 1, 2, 3, 4]; 17 | for n in 0..5 { 18 | thrad::spawn(|| { 19 | println!("{}", nums[n]); 20 | }); 21 | } 22 | } 23 | ``` 24 | 25 |   26 | 27 | 在上述代码中,`vec`中包含5个数字,然后生成5个线程,其中每个线程都会访问`vec`中的数据。 28 | 29 | ```bash 30 | Checking ddd v0.1.0 (/root/rs/ddd) 31 | error[E0373]: closure may outlive the current function, but it borrows `nums`, which is owned by the current function 32 | --> src/main.rs:9:23 33 | | 34 | 9 | thread::spawn(|| { 35 | | ^^ may outlive borrowed value `nums` 36 | 10 | println!("{}", nums[n]); 37 | | ---- `nums` is borrowed here 38 | | 39 | help: to force the closure to take ownership of `nums` (and any other referenced variables), use the `move` keyword 40 | ``` 41 | 42 | `nums`来自主线程,当我们生成一个线程时,它不能保证在父线程已经失效,它指向的`Vec`也会被释放。如果Rust允许前面的代码通过编译,那么子线程可能已经访问了主线程返回后包含一些垃圾值的`nums`,并且可能导致分段错误。 43 | 44 | 可以使用同步和互斥锁方解决该问题。 45 | 46 | ```rust 47 | use std::thread; 48 | use std::sync::{Mutex, Arc}; 49 | 50 | fn main() { 51 | let nums = vec![0, 1, 2, 3, 4]; 52 | let data = Arc::new(Mutex::new(nums)); // 保证数据原子性 53 | let mut handlers = vec![]; // 存储子线程 54 | 55 | for n in 0..5 { 56 | let d = Arc::clone(&data); // 克隆原子引用 57 | 58 | // 启动线程 59 | let h = thread::spawn(move || { // d 所有权转移 60 | let v = d.lock().unwrap(); 61 | 62 | println!("{}", v[n]); 63 | }); 64 | 65 | handlers.push(h); // 收集子线程 66 | } 67 | 68 | handlers.into_iter().for_each(|h| h.join().unwrap()); // 等待所有子线程结束 69 | } 70 | ``` 71 | 72 | ### 所有权转移 73 | 74 | 使用关键字 `move` 从父线程中将值移动到其子线程中。 75 | 76 | ```rust 77 | use std::thread; 78 | 79 | fn main() { 80 | let my_str = String::from("Damn you borrow checker!"); 81 | let _ = thread::spawn(move || { 82 | println!("In thread: {}", my_str); 83 | }); 84 | 85 | println!("In main: {}", my_str); 86 | } 87 | ``` 88 | 89 | 在 **父线程** 中再次访问 `my_str`,此操作将失败,并显示以下错误提示: 90 | 91 | 92 | ```bash 93 | $> cargo c 94 | Checking ddd v0.1.0 (/root/rs/ddd) 95 | error[E0382]: borrow of moved value: `my_str` 96 | 11 | println!("In main: {}", my_str); 97 | | ^^^^^^ value borrowed here after move 98 | ``` 99 | 100 | 使用 `move` 关键字,发生所有权转移。即使我们只是从子线程中读取`my_str`,该数据也不再有效。 101 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/actor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/并发/actor.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/同步/同步.md: -------------------------------------------------------------------------------- 1 | # 同步 2 | 3 | 通道是单所有权,一旦值被发送,将无法再次使用。某些时候,内存共享有实际需求。标准库提供 **互斥体** 用于资源和逻辑保护。但面对多线程共享时,需额外的 **原子引用计数** 来启用多所有权。 4 | 5 |   6 | 7 | * `Mutex`: 任意时刻,仅有一个线程可以访问资源。 8 | * `Arc`: 支持并发的原子引用计数。 9 | 10 | ```rust 11 | use std::thread; 12 | use std::sync::{Mutex, Arc}; 13 | 14 | fn main() { 15 | // 以原子引用计数包装的互斥体 16 | let data = Arc::new(Mutex::new(vec![])); // 共享数据 17 | let mut handlers = vec![]; 18 | 19 | for _i in 1..3 { 20 | // 克隆原子引用 21 | let d = Arc::clone(&data); 22 | 23 | // 启动线程 24 | let h = thread::spawn(move || { 25 | 26 | // 加锁,并返回被保护的数据 27 | let mut v = d.lock().unwrap(); 28 | 29 | // 修改数据 30 | for i in 1..=10 { 31 | v.push(i); 32 | } 33 | }); // drop: 自动释放锁 34 | 35 | handlers.push(h); 36 | } 37 | 38 | // 等待线程结束 39 | handlers.into_iter().for_each(|h| h.join().unwrap()); 40 | 41 | // 查看结果 42 | println!("{:?}", data.lock().unwrap()); 43 | } 44 | ``` 45 | 46 | 在智能指针一节中,我们用`Rc` 来实现可变所有权共享,但那并不是并发安全的。从这点上说,`Arc` 就是它的线程安全版。 47 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/并行/scalar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/并发/并行/scalar.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/并行/simd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/并发/并行/simd.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/并行/垂直计算.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/并发/并行/垂直计算.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/并行/水平计算.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/并发/并行/水平计算.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/并行/计算机系统结构.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/并发/并行/计算机系统结构.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/异步/Future/imgs/Future调度流程图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/并发/异步/Future/imgs/Future调度流程图.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/异步/Future/move.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/并发/异步/Future/move.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/异步/Future/move_swap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/并发/异步/Future/move_swap.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/异步/Future/waker.md: -------------------------------------------------------------------------------- 1 | # Waker 2 | 3 | `futures` 在第一次被 `poll` 时无法完成任务是很常见的。遇到这种情况,`futures` 需要将任务执行的现场保护起来,等待下次唤醒(通过 `Waker` 进行唤醒),继续执行任务。 4 | 5 | `Waker` 提供了一种 `wake()` 方法,用于唤醒休眠中的任务。 6 | 7 | `Waker` 还实现了 `clone()`, 以便复制和存储任务。 8 | 9 |   10 | 11 | ## 构建定时器 12 | 13 | ```rust 14 | use { 15 | std::{ 16 | future::Future, 17 | pin::Pin, 18 | sync::{Arc, Mutex}, 19 | task::{Context, Poll, Waker}, 20 | thread, 21 | time::Duration, 22 | }, 23 | }; 24 | 25 | pub struct TimerFuture { 26 | // `Arc>` 共享值在线程和 `Future` 之间进行通信 27 | shared_state: Arc>, 28 | } 29 | 30 | // `future`与等待线程之间的共享状态 31 | struct SharedState { 32 | // 判断任务是否就绪 33 | completed: bool, 34 | 35 | // 任务唤醒者 36 | waker: Option, 37 | } 38 | ``` 39 | 40 |   41 | 42 | ### `Future`具体实现 43 | 44 | ```rust 45 | impl Future for TimerFuture { 46 | type Output = (); 47 | 48 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 49 | // Pin:保证mut Self不会发生move!!! 50 | 51 | let mut shared_state = self.shared_state.lock().unwrap(); 52 | if shared_state.completed { 53 | // 任务执行完成 54 | Poll::Ready(()) 55 | } else { 56 | // 设置唤醒器, 以便线程在计时器(timer)过期的时候可以唤醒当前任务 57 | shared_state.waker = Some(cx.waker().clone()); 58 | Poll::Pending 59 | } 60 | } 61 | } 62 | ``` 63 | 64 | 如果线程设置 `shared_state.completed = true`, 任务执行完成;否则为当前任务克隆 `LocalWaker`,将其转换为 `Waker`,然后传递给 `shared_state.waker`,等待当前任务被唤醒。 65 | 66 | 在每次轮训(`Poll`)时更新 `Waker`,因为 `Future` 可能已经转移到另一个不同的任务与 `Waker`。`Future` 被轮询之后在任务间传递时会发生这种情况。 67 | 68 |   69 | 70 | ### 构造计时器并启动线程 71 | 72 | ```rust 73 | impl TimerFuture { 74 | // 创建一个新的 `TimerFuture`,在timeout之后,任务完成 75 | pub fn new(duration: Duration) -> Self { 76 | let shared_state = Arc::new(Mutex::new(SharedState{ 77 | completed: false, 78 | waker: None, 79 | })); 80 | 81 | // 创建一个新的线程 82 | let thread_shared_state = shared_state.clone(); 83 | thread::spawn(move || { 84 | thread::sleep(duration); 85 | let mut shared_state = thread_shared_state.lock().unwrap(); 86 | 87 | // 唤醒一个future任务 88 | shared_state.completed = true; 89 | if let Some(waker) = shared_state.waker.take() { 90 | waker.wake() 91 | } 92 | }); 93 | 94 | TimerFuture { shared_state } 95 | } 96 | } 97 | ``` 98 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/异步/async_await/README.md: -------------------------------------------------------------------------------- 1 | # async/await 2 | 3 | future-rs第三方库经历了三个阶段迭代: 4 | 5 | * 0.1 版本中,通过 `then` 和 `and_then` 方法实现 `Future` 异步计算的执行顺序(这种方式会导致很多混乱的嵌套和回归链,不利于开发体验)。 6 | * 0.2 版本引入了 `async/await`方案解决以上存在的问题。 7 | * 经过两个阶段迭代,目前 `async/await` 处于 0.3 版本。 8 | 9 | ## futures-rs 两种写法对比 10 | 11 | `futures-rs 0.1` 版本,需要先执行`pull_down_tweets`异步函数,再执行`write_tweets`异步函数,这种写法使用`and_then`构成了很长的调用链。 12 | 13 | `rutures-rs 0.3` 版本,使用了`async/await!`,在语义上要比使用`and_then`更加直观和简单。Rust当前以`async`关键字配合`await!`宏提供`async/await`异步方案。 14 | 15 | ```rust 16 | // futures-rs 0.1 17 | fn download_and_write_tweets( 18 | user: String, 19 | socket: Socket, 20 | ) -> impl Future> { 21 | pull_down_tweets(user).and_then(move |tweets| write_tweets(socket)) 22 | } 23 | 24 | // futures-rs 0.3 25 | async fn download_and_write_tweets( 26 | user: &str, 27 | socket: &Socket, 28 | ) -> io::Result<()> { 29 | let tweets = await!(pull_down_tweets(user))?; 30 | await!(write_tweets(socket)) 31 | } 32 | ``` 33 | 34 |   35 | 36 | ## async/await实现原理 37 | 38 | `async/await` 是一种语法糖,`async fn` 会自动为开发者生成返回值是 `impl Future`类型的函数。Rust不仅支持 `async fn` 定义的异步函数,而且还支持`async block`异步块。 39 | 40 | ```rust 41 | let my_future = async { 42 | await!(prev_async_func); 43 | println!("Hello from an async block"); 44 | } 45 | ``` 46 | 47 | 如上实例,直接使用 `async` 块创建一个 `Future`。实际上,使用`async fn`函数在底层也是由 `async` 块生成`Future`的,具体执行过程如下: 48 | 49 | ![future](./imgs/future.png) 50 | 51 | Rust 将 `async fn`或`async block` 异步块代码解析为AST后,在HIR层都会转换为`async` 块的形式。 52 | 53 | * 首先,将 `async` 块生成一个 `Generator` 类型的生成器使用 54 | * 然后,将该生成器通过 `GenFuture` 结构体进行包装,得到一个`GenFuture>(T)`类型 55 | * 最后,为该`GenFuture`实现`Future` 56 | 57 | 如下为`GenFuture` 实现 `Future`源码: 58 | 59 | ```rust 60 | impl> Future for GenFuture { 61 | type Output = T::Return; 62 | 63 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 64 | // Pin::map_unchecked_mut 函数返回一个 &mut self 类型,等价于 &mut self.0.resume() 65 | let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) }; 66 | 67 | // 匹配resume方法的调用结果,轮询Future的计算结果 68 | match gen.resume(ResumeTy(NonNull::from(cx).cast::>())) { 69 | // 将实现了Future的GenFuture作为返回值插入编译器生成的代码中 70 | GeneratorState::Yielded(()) => Poll::Pending, 71 | GeneratorState::Complete(x) => Poll::Ready(x), 72 | } 73 | } 74 | } 75 | ``` 76 | 77 | 以上就是 `async` 语法糖在编译器内部转化作为返回类型 `GenFuture` 的整个过程。当然,还需要 `await!` 宏相互配合才可以。`await!` 宏原理原理如下: 78 | 79 | ![future](./imgs/future2.png) 80 | 81 | `await!` 宏必须在 `async` 块中使用,不能单独使用。因为 `await!` 宏实际展开的代码要在 `loop` 循环中对轮询结果进行判断。如果`Ready` 状态,则跳出 `loop` 循环;如果是 `Pending` 状态,则生成 `yield`。正因为 `yield`,才允许 `async` 块生成一个 `Generator` 类型生成器。 82 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/异步/async_await/async和await.md: -------------------------------------------------------------------------------- 1 | # `async`和`await!` 2 | 3 | `async/await!` 是Rust语法的特殊部分,可以实现多执行任务的异步执行。 4 | 5 | ## async使用方法 6 | 7 | * `async fn` 8 | * `async block` 9 | * `async closure` 10 | 11 | 以上三种使用方法,返回一个实现 `Future` 特征的值。 12 | 13 | ```rust 14 | // 返回一个实现 `Future` 的结构体 15 | async fn foo() -> u8 { 16 | 5 17 | } 18 | 19 | fn bar() -> impl Future { 20 | async { 21 | let x: u8 = await!(foo()); 22 | x + 5 23 | } 24 | } 25 | 26 | fn bar() -> impl Future { 27 | let closure = async |x: u8| { 28 | await!(bar() + x) 29 | }; 30 | closure(5) 31 | } 32 | ``` 33 | 34 | 使用 `await!` 运行 Future,如果 `Future` 被阻塞, 它将让出当前线程。当再次获取CPU时间片时,执行者获取 `Future` 继续执行。 35 | 36 |   37 | 38 | ## async 生命周期 39 | 40 | `async fn` 与传统函数不同,传递引用参数或其它非 `'static` 参数时,返回一个受参数生命周期限制的 `Future`: 41 | 42 | ```rust 43 | async fn foo(x: &u8) -> u8 { 44 | *x 45 | } 46 | 47 | fn foo<'a>(x: &'a u8) -> impl Future + 'a { 48 | async { 49 | *x 50 | } 51 | } 52 | ``` 53 | 54 | 返回的 `Future` 立即被 `await!` 执行(非 `'static` 参数),生命周期仍然有效。如果将 `Future` 发送到其它线程,可能存在生命周期问题。 55 | 56 | ```rust 57 | use core::future::Future; 58 | 59 | async fn foo(x: &u8) -> u8 { 60 | *x 61 | } 62 | 63 | fn good() -> impl Future { 64 | async { 65 | let x = 5; 66 | let _ = foo(&x).await; 67 | } 68 | } 69 | 70 | fn main() { 71 | let _ = good(); 72 | } 73 | ``` 74 | 75 | 通过将参数移动到 `async` 块中,生命周期延长到与调用 `foo` 返回 `Future` 的生命周期相匹配。 76 | 77 |   78 | 79 | ### async move 80 | 81 | `async move` 块将获取它引用变量的所有权,生命周期和`Future`相绑定,但该变量所有权为该`Future`独享。 82 | 83 | ```rust 84 | fn foo() -> impl Future { 85 | let my_string = "foo".to_string(); 86 | async move { 87 | ... 88 | println!{"{}", my_string}; 89 | } 90 | } 91 | ``` 92 | 93 |   94 | 95 | ### `await!` 多线程执行者 96 | 97 | 使用多线程 `Future` 执行者时, `Future` 可能在多线程之间移动,因此在 `async` 作用域内使用的任何变量都必须能够在线程之间传递,因为任何 `await!` 变量都可能导致切换到新线程。 98 | 99 | 非安全: 100 | 101 | * `Rc, &RefCell` 102 | * 没有实现 `Send` 特征的类型 103 | * 引用参数未实现 `Sync` 特征的类型 104 | 105 | 在 `await!` 作用域内要使用 `futures::lock` 中的 `Mutex`,而不要使用 `std::sync`中的 `Mutex`,防止产生死锁问题。 106 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/异步/async_await/imgs/TCP-IP详解卷1:协议.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/并发/异步/async_await/imgs/TCP-IP详解卷1:协议.pdf -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/异步/async_await/imgs/future.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/并发/异步/async_await/imgs/future.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/异步/async_await/imgs/future2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/并发/异步/async_await/imgs/future2.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/异步/yield/生成器执行流程图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/并发/异步/yield/生成器执行流程图.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/消息/消息.md: -------------------------------------------------------------------------------- 1 | # 消息 2 | 3 | 以 **通道**(channel) 在不同线程间传递消息。 4 | 5 | ```rust 6 | use std::thread; 7 | use std::sync::mpsc::channel; 8 | 9 | fn main() { 10 | let data = vec![1, 2, 3, 4]; // 数据 11 | let (tx, rx) = channel(); // 消息通道 12 | 13 | // 生产者 14 | let send = thread::spawn(move || { 15 | for d in data { 16 | tx.send(d).unwrap(); 17 | } 18 | }); 19 | 20 | // 消费者 21 | let recv = thread::spawn(move || { 22 | for v in rx { 23 | println!("{}", v); 24 | } 25 | }); 26 | 27 | // 等待所有子线程结束 28 | send.join().unwrap(); 29 | recv.join().unwrap(); 30 | } 31 | ``` 32 | 33 |   34 | 35 | 标准库mpsc是多生产者、单消费者的FIFO队列,通过 `clone` 创建多个生产者。当所有生产者结束(drop),通道关闭。 36 | 37 | ```rust 38 | use std::thread; 39 | use std::sync::mpsc::{Sender, channel}; 40 | 41 | fn main() { 42 | let mut handlers = vec![]; 43 | let (tx, rx) = channel(); 44 | 45 | // 多生产者 46 | for i in 1..=10 { 47 | let t = Sender::clone(&tx); 48 | let h = thread::spawn(move || { 49 | t.send(i).unwrap(); 50 | }); 51 | 52 | handlers.push(h); 53 | } 54 | 55 | // 销毁多余的生产者 56 | drop(tx); 57 | 58 | // 接收数据 59 | rx.into_iter().for_each(|v| println!("{}", v)); 60 | 61 | // 等待结束 62 | handlers.into_iter().for_each(|h| h.join().unwrap()); 63 | 64 | println!("exit."); 65 | } 66 | ``` 67 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/线程/Actor模型.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/并发/线程/Actor模型.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/线程/atomic.md: -------------------------------------------------------------------------------- 1 | # 原子类型(Atomic) 2 | 3 | 互斥锁(`Mutex`)、读写锁(`RWLock`)等同步事件(原语)确实可以满足基本的线程安全需求,但是有时候使用锁会影响性能,甚至存在死锁之类的风险,因此引入原子类型。 4 | 5 | 原子类型内部封装了编程语言和操作系统的「契约」,基于此「契约」来实现一些自带原子操作的类型,而不需要对其使用锁来保证原子性,从而实现无锁(`Lock-Free`)并发编程。这种契约就是**多线程内存模型**,Rust的多线程内存模型借鉴了`C++ 11`,它保证了多线程并发的顺序一致性,不会因为底层的各种优化重排行为而失去原子性。 6 | 7 | 原子性操作类型: 8 | 9 | * `Load`:从一个原子类型内部读取值。 10 | * `Store`:往一个原子类型内部写入值。 11 | * 「读取-修改-写入」操作: 12 | * `CAS(Compare-And-Swap)`:比较并交换。 13 | * `Swap`:原子交换操作。 14 | * `Compare-Exchange`:比较/交换操作。 15 | * `Fetch-*`:`fetch_add`、`fetch_sub`、`fetch_and`、`fetch_or` 等一系列原子的加减或逻辑运算。 16 | 17 |   18 | 19 | ## Rust提供原子类型 20 | 21 | Rust标准库 `std::sync::atomic` 模块中提供了4个原子类型:`AtomicBool`、`AtomicIsize`、`AtomicPtr` 和 `AtomicUsize`。 22 | 23 | 使用原子类型实现一个简单自旋锁(`Spinlock`)。 24 | 25 | ```rust 26 | use std::sync::Arc; 27 | use std::sync::atomic::{AtomicUsize, Ordering}; 28 | use std::thread; 29 | 30 | fn main() { 31 | // 原子类型本身虽然可以保证原子性,但它自身不提供在多线程中共享的方法 32 | // 需要使用 Arc 将其跨线程共享 33 | let spinlock = Arc::new(AtomicUsize::new(1)); 34 | let spinlock_clone = spinlock.clone(); 35 | let thread = thread::spawn(move || { 36 | // 使用pinlock_clone的store方法,将其内部AtomicUsize类型值写为0 37 | spinlock_clone.store(0, Ordering::SeqCst); 38 | }); 39 | 40 | // main主线程使用spinlock的load方法读取内部原子类型的值,如果不为0 41 | // 则不停地循环测试读取锁的状态,直到其状态被设置为0为止(自旋锁) 42 | while spinlock.load(Ordering::SeqCst) != 0 {} 43 | 44 | // 使用join方法阻塞main主线程等待子线程完成 45 | if let Err(panic) = thread.join() { 46 | println!("Thread had an error: {:?}", panic); 47 | } 48 | } 49 | ``` 50 | 51 |   52 | 53 | ## 内存顺序 54 | 55 | 原子类型除了提供基本的原子操作之外,还提供了内存顺序参数。每个原子类型虽然对开发者而言是一个“黑盒”,但也可以通过提供内存顺序参数来控制底层线程执行顺序。控制内存顺序实际上就是控制底层线程同步,以便消除底层因为编译器优化或者指令重排而可能引发的竞态条件。 56 | 57 | `std::sync::atomic::Ordering` 模块中定义了Rust支持的5种内存顺序,可以将其分为三大类: 58 | 59 | * **排序一致性顺序**:`Ordering::SeqCst` 60 | * **自由顺序**:`Ordering::Relaxed` 61 | * **获取-释放顺序**:`Ordering::Release`、`Ordering::Acquire` 和 `Ordering::AcqRet` 62 | 63 | ```rust 64 | // library/core/src/sync/atomic.rs 65 | pub enum Ordering { 66 | Relaxed, 67 | Release, 68 | Acquire, 69 | AcqRel, 70 | SeqCst, 71 | } 72 | ``` 73 | 74 | Rust支持的5种内存顺序与底层的LLVM支持的内存顺序是一致的。 75 | 76 |   77 | 78 | ### 排序一致性顺序(SeqCst) 79 | 80 | 排序一致性顺序,也就是指定 `Ordering::SeqCst`的原子操作,都必须是先存储(store)再加载(load)。多线程下,所有原子写操作都必须在读操作之前完成。通过这种规定,强行指定了底层多线程的执行顺序,从而保证了多线程中所有操作的全局一致性。但需要付出代价的,这种方式需要所有的线程进行全局同步,存在性能消耗。 81 | 82 | 日常开发中如何选择内存顺序和底层硬件环境也有关系,一般情况下建议使用 `Ordering::SeqCst`。在需要性能优化的情况下,先调研硬件环境,再优先选择获取-释放顺序(`Ordering::Relase`、`Ordering::Acquire` 和 `Ordering::AcqRel`)。除非必要,否则不要使用 `Ordering::Relaxed`。 83 | 84 |   85 | 86 | ### 自由顺序(Release) 87 | 88 | **自由顺序** 与排序一致性顺序相反,线程只进行原子操作,但线程之间会存在竞态条件。使用这种内存顺序比较危险的,只有在明确了使用场景且必须使用它的情况下(Eg:只有读操作),才可使用自由顺序。 89 | 90 |   91 | 92 | ### 获取-释放顺序(load-store) 93 | 94 | **获取-释放顺序是除排序一致性之外的优先选择**。这种内存顺序并不会对全部的线程进行统一强制性的执行顺序要求。在该内存顺序内,`store` 代表释放(Release),`load` 代表获取(Acquire),通过这两种操作的协作实现线程同步。 95 | 96 | 进行释放(`Ordering::Release`)操作时,之前所有的获取(`Ordering::Acquire`)操作都是可见的;进行获取(`Ordering::Acquire`)操作时,之前所有释放(`Ordering::Release`)操作都是可见的。`Ordering::AcqRel`代表读时使用 `Ordering::Acquire`,写时使用`Ordering::Release`操作。 97 | 98 | 获取-释放顺序虽然不像排序一致性顺序那样对全局线程统一排序,但是它让每个线程都按固定的顺序执行。 99 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/线程/barrier.md: -------------------------------------------------------------------------------- 1 | # 屏蔽(barrier) 2 | 3 | 大多数现代计算机为了提高性能而采取乱序执行,这使得内存屏蔽成为必然。内存屏障(Memory barrier) 是一类同步屏蔽指令,它使得CPU或编译器在对内进行操作的时候,严格按照一定的顺序来执行,也就是说在内存屏蔽之前的指令和之后的指令不会由于系统优化等原因而导致乱序。 4 | 5 | 内存屏蔽之前的所有写操作都要写入内存;内存屏蔽之后的读操作都可以获得同步屏障之前的写操作结果。因此,对于敏感的程序块,写操作之后、读操作之前可以插入内存屏障。 6 | 7 |   8 | 9 | ## rust 内存屏障 10 | 11 | Rust中屏蔽的用法和互斥锁类似,它可以通过`wait`方法在某个点阻塞全部进入临界区的线程。 12 | 13 | ```rust 14 | use std::sync::{Arc, Barrier}; 15 | use std::thread; 16 | 17 | fn main() { 18 | let mut handles = Vec::with_capacity(5); 19 | let barrier = Arc::new(Barrier::new(5)); 20 | for _ in 0..5 { 21 | let c = barrier.clone(); 22 | handles.push(thread::spawn(move || { 23 | println!("before wait"); 24 | 25 | // 阻塞所有线程,当都执行到临界区,继续执行 26 | c.wait(); 27 | println!("after wait"); 28 | })); 29 | } 30 | 31 | for handle in handles { 32 | handle.join().unwrap(); 33 | } 34 | } 35 | ``` 36 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/线程/channel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/并发/线程/channel.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/线程/convar.md: -------------------------------------------------------------------------------- 1 | # 条件变量 2 | 3 | **条件变量** 跟屏障有点儿相似,但它不是阻塞全部线程,而是在满足指定条件之前阻塞某一个得到互斥锁的线程。 4 | 5 | ```rust 6 | use std::sync::{Arc, Condvar, Mutex}; 7 | use std::{thread, time}; 8 | 9 | fn main() { 10 | // 互斥锁和条件变量,声明 Arc, Condvar> 类型的变量 11 | let pair = Arc::new((Mutex::new(false), Condvar::new())); 12 | let pair_clone = pair.clone(); 13 | thread::spawn(move || { 14 | // 得到互斥锁lock,通过lock方法获得互斥锁 15 | let &(ref lock, ref cvar) = &*pair_clone; 16 | let mut started = lock.lock().unwrap(); 17 | 18 | println!("children thread started. {}", started); 19 | let three_seconds = time::Duration::from_secs(3); 20 | thread::sleep(three_seconds); 21 | 22 | // 修改其中包含的 bool 类型数据为true 23 | // 修改之后,通过notify_one 方法通知主线程: 通知主线程,第33行 24 | *started = true; 25 | cvar.notify_one(); 26 | }); 27 | 28 | let &(ref lock, ref cvar) = &*pair; 29 | let mut started = lock.lock().unwrap(); 30 | 31 | while !*started { 32 | println!("{}", started); 33 | 34 | // wait方法,阻塞当前main主线程,直到子线程中 started 互斥体中的条件为真 35 | started = cvar.wait(started).unwrap(); 36 | println!("{}", started); 37 | } 38 | } 39 | ``` 40 | 41 | **在运行中每个条件变量只能和一个互斥体一起使用。** 在有些线程需要获取某个状态成立的情况下,如果单独使用互斥锁会比较浪费系统资源,因为只有多次出入临界区才能获取到某个状态的信息。此时就可以配合使用条件变量,当状态成立时通知互斥体就可以,因此减少了系统资源的浪费。 42 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/线程/rwlock.md: -------------------------------------------------------------------------------- 1 | # 读写锁(rwLock) 2 | 3 | 读写锁(`RwLock`)和互斥锁(`Mutex`)十分类似,不同在于`RwLock` 对线程进行**读者(Reader)** 和 **写者(Writer)** 的区分,不像 `Mutex` 只能独占访问。 4 | 5 | 该锁支持多个读者线程和一个写者线程,其中读线程只允许进行只读访问,而写线程只能进行独占写操作。只要线程没有拿到写锁,`RwLock`就允许任意数量的读线程获得读锁。 6 | 7 | 和 `Mutex` 一样,`RwLock` 也会因为panic而“中毒”。 8 | 9 |   10 | 11 | ### 读写锁实例 12 | 13 | ```rust 14 | use std::sync::RwLock; 15 | 16 | fn main() { 17 | let lock = RwLock::new(5); 18 | 19 | { 20 | let r1 = lock.read().unwrap(); 21 | let r2 = lock.read().unwrap(); 22 | assert_eq!(*r1, 5); 23 | assert_eq!(*r2, 5); 24 | } 25 | 26 | { 27 | let mut w = lock.write().unwrap(); 28 | *w += 1; 29 | assert_eq!(*w, 6); 30 | } 31 | } 32 | ``` 33 | 34 | **读锁和写锁要使用显示作用域块隔开**,这样的话,读锁或写锁才能在离开作用域之后自动释放;否则会引起死锁,因为**读锁和写锁不能同时存在**。 35 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/线程/thread_pool.md: -------------------------------------------------------------------------------- 1 | # 线程池(ThreadPool) 2 | 3 | 多线程并发更常见的方式是使用线程池。线程虽然比进程轻量,但如果每次处理任务都要更新创建线程的话,就会导致线程过多,从而带来更多的创建和调度的开销。**采用线程池的方式,不仅可以实现对线程的复用,避免多次创建、销毁线程的开销,而且还能保证内核可以被充分利用。** 4 | 5 | 实现一个线程池需要考虑以下几点: 6 | 7 | * **工作线程**:用于处理具体任务的线程。 8 | * **线程池初始化**:通过设置参数指定线程池的初始化栈大小、名称、工作线程数等。 9 | * **待处理任务的存储队列**:工作线程数是有限的,对于来不及处理的任务,需要暂时保存到一个队列中。 10 | * **线程池管理**:管理线程池的任务数和工作线程的状态。比如,在没有空闲工作线程时,则需要等待,或者在需要时阻塞主线程等待所有任务执行完毕。 -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/线程/unsafeCell.md: -------------------------------------------------------------------------------- 1 | # 内部可变性 2 | 3 | Rust中提供的并发编程中,基本都支持内部可变性, 在行为上与 `Cell`、`RefCell` 比较相似。 4 | 5 | ```rust 6 | // Mutex 源码实现 7 | 8 | pub type MovableMutex = Box; 9 | 10 | pub struct Mutex { 11 | // 包装了用于底层操作系统API的sys::MovableMutex 12 | inner: sys::MovableMutex, 13 | 14 | // 标记该锁是否已经中毒(获取锁后,发生panic) 15 | poison: poison::Flag, 16 | 17 | // 锁包含的数据,使用 UnsafeCell 18 | data: UnsafeCell, 19 | } 20 | ``` 21 | 22 | 内部可变性的结构体都是基于 `Unsafe`实现的。`Unsafe` 是一个泛型结构体,它属于**语言项(Lang Item)**,编译器会对它进行特殊处理。一般来讲,Rust中将不可变借用转换为可变借用**属于未定义行为**,编译器不允许开发者随意对这两种引用进行互相转换。但是,`UnsafeCell` 是唯一的例外,这也是`UnsafeCell`属于语言项的原因,**它属于Rust中将不可变转换为可变的唯一合法渠道,对于使用了 `UnsafeCell` 的类型,编译器会关闭相关的检查**。 23 | 24 | ```rust 25 | // UnsafeCell 源码实现 26 | 27 | #[lang = "unsafe_cell"] 28 | pub struct UnsafeCell { 29 | value: T, 30 | } 31 | 32 | impl !Sync for UnsafeCell {} 33 | 34 | impl UnsafeCell { 35 | pub const fn get(&self) -> *mut T { 36 | self as *const UnsafeCell as *const T as *mut T 37 | } 38 | } 39 | ``` 40 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/并发/线程/代码执行流程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/并发/线程/代码执行流程.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/所有权/Borrow.md: -------------------------------------------------------------------------------- 1 | # Borrow, BorrowMut, ToOwned 2 | 3 | 某些类型通过对数据类型的引用提供对底层的访问,该种类型属于 `borrow`类型,例如,可以将 `Box` 借用为 `T`; 将 `String` 借用为 `str`。 4 | 5 | Rust提供了类型转换为`borrow`的能力。 6 | 7 |   8 | 9 | ## Borrow 10 | 11 | `Borrow`提供了一个 `.borrow()` 方法,可以对具体数据类型转换为引用类型。`Borrow` 的前后类型之间要求必须内部等价性(比如: String和&str类型),不具有这个等价性的两个类型之间,不能实现 `Borrow`。 12 | 13 | `AsRef` 更通用,更普遍,覆盖类型更多,是 `Borrow`的超集。 14 | 15 | ```rust 16 | use std::borrow::Borrow; 17 | 18 | fn check>(s: T) { 19 | assert_eq!("Hello", s.borrow()); 20 | } 21 | 22 | fn main() { 23 | let s = "Hello".to_string(); 24 | check(s); 25 | 26 | let s = "Hello"; 27 | check(s); 28 | } 29 | ``` 30 | 31 | ```x86asm 32 | ; let s = "Hello".to_string(); 33 | (gdb) ptype s 34 | type = struct alloc::string::String { 35 | vec: alloc::vec::Vec, 36 | } 37 | 38 | ; s = "Hello" 39 | (gdb) ptype s 40 | type = struct &str { 41 | data_ptr: *mut u8, 42 | length: usize, 43 | } 44 | ``` 45 | 46 |   47 | 48 | ## BorrowMut 49 | 50 | `BorrowMut` 提供了一个方法 `.borrow_mut()`, 它是 `Borrow` 的可变(mutable) 引用版本。 51 | 52 | 一个类型为 `T` 的值 `foo`,如果 `T` 实现了 `BorrowMut`,那么 `foo` 可执行 `.borrow_mut()` 操作,即 `foo.borrow_mut()`。操作的结果我们得到类型为 `&mut U` 的一个可变(mutable) 引用。 53 | 54 | ```rust 55 | use std::borrow::BorrowMut; 56 | 57 | fn check>(mut v: T) { 58 | assert_eq!(&mut [1, 2, 3], v.borrow_mut()); 59 | } 60 | 61 | fn main() { 62 | let v = vec![1, 2, 3]; 63 | 64 | check(v); 65 | } 66 | ``` 67 | 68 |   69 | 70 | ## ToOwned 71 | 72 | `ToOwned` 特征针对可以转换为所有权版本的类型实现。例如, `&str` 类型为 `String` 实现了这个特征。这意味着 `&str` 类型有一个名为 `to_owned` 的函数,它可以将其转换为 `String` 类型,这是一种包含所有权的类型。 73 | 74 | 通常可使用 `Clone` 将某些类型从借用变为 `owned`。但是 `Clone` 仅适用于从 `&T` 到 `T`。 `ToOwned`包括了类型转换拥有的数据。 75 | 76 | ```rust 77 | fn main() { 78 | let s: &str = "a"; 79 | let ss: String = s.to_owned(); 80 | 81 | let v: &[i32] = &[1, 2]; 82 | let vv: Vec = v.to_owned(); 83 | 84 | println!("{:}, {:?}", ss, vv); 85 | } 86 | ``` 87 | 88 | ```x86asm 89 | ; let s: &str = "a"; 90 | (gdb) ptype s 91 | type = struct &str { 92 | data_ptr: *mut u8, 93 | length: usize, 94 | } 95 | 96 | ; let ss: String = s.to_owned(); 97 | (gdb) ptype ss 98 | type = struct alloc::string::String { 99 | vec: alloc::vec::Vec, 100 | } 101 | 102 | ; let v: &[i32] = &[1, 2]; 103 | (gdb) ptype v 104 | type = struct &[i32] { 105 | data_ptr: *mut i32, 106 | length: usize, 107 | } 108 | 109 | ; let vv: Vec = v.to_owned(); 110 | (gdb) ptype vv 111 | type = struct alloc::vec::Vec { 112 | buf: alloc::raw_vec::RawVec, 113 | len: usize, 114 | } 115 | ``` 116 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/所有权/README.md: -------------------------------------------------------------------------------- 1 | # 所有权 2 | 3 | 一个值的所有权被转移给另外一个变量的绑定过程,就叫做所有权转移。 4 | 5 | Rust中每一个值都有一个所有者,也就是说Rust中分配的每块内存都有其所有者,**所有者负责该内存的释放和读写权限**,并且每次每个值只能有唯一的所有者。这就是Rust的所有权机制(OwnerShip)。 6 | 7 | ## 所有权机制(OwnerShip) 8 | 9 | Rust中,可以通过是否实现`Copy` trait进行区分数据类型是**值语义**还是**引用语义**。Rust也引入了新的语义:**复制(Copy)语义** 和 **移动(Move)语义**。 10 | 11 | **复制语义**对应值语义来理解,也就是说,实现了 `Copy` 的类型在进行按位复制时是安全的;**移动语义**可以对应引用语义来理解,也就是说,在其他语言(C++)中本来是引用语义的类型,在Rust中不允许按位复制,只允许移动所有权,只有这样才能保证安全。这样划分是因为引入了所有权机制,在所有权机制下同时保证内存安全和性能。 12 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/所有权/moveship_copy_stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/所有权/moveship_copy_stack.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/数据/字符串/encode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/数据/字符串/encode.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/数据/字符串/字符串_String.md: -------------------------------------------------------------------------------- 1 | # 字符串_String 2 | 3 | String包含所有权类型,意味着保存String值的变量是其所有者。由于 String 是在堆上分配的,因此它可以被修改,并且能够在运行时根据需要增加长度。堆分配是一种开销相对昂贵的操作,`Vec` 分配内存时使该成本按使用量平摊而降低。 4 | 5 | ```rust 6 | fn main() { 7 | let a: String = "Hello".to_string(); 8 | let b = String::from("Hello"); 9 | let c = "World".to_owned(); 10 | let d = c.clone(); 11 | 12 | println!("{}, {}, {}, {}", a, b, c, d); 13 | } 14 | ``` 15 | 16 | ```x86asm 17 | (gdb) ptype a 18 | type = struct alloc::string::String { 19 | vec: alloc::vec::Vec, 20 | } 21 | (gdb) ptype b 22 | type = struct alloc::string::String { 23 | vec: alloc::vec::Vec, 24 | } 25 | (gdb) ptype c 26 | type = struct alloc::string::String { 27 | vec: alloc::vec::Vec, 28 | } 29 | (gdb) ptype d 30 | type = struct alloc::string::String { 31 | vec: alloc::vec::Vec, 32 | } 33 | ``` 34 | 35 | ```rust 36 | // 数据结构 37 | 38 | String heap 39 | +=======+ +=========//========+ 40 | | ptr | --------> | u8 data ... | 41 | +-------+ +=========//========+ 42 | | cap | 43 | +-------+ 44 | | len | 45 | +=======+ 46 | ``` 47 | 48 |   49 | 50 | ## String 标准库 51 | 52 | String在标准库中还包含很多便捷方法: 53 | 54 | * `String::new()`:分配一个空的String类型。 55 | * `String::from(s: &str)`: 分配一个新的String类型,并通过字符串切片来填充它。 56 | * `String::with_capacity(capacity: usize)`:预先分配一个预定义大小、空的String类型。 57 | * `String::from_utf8(vec: Vec)`:从bytestring分配一个新的String类型。 58 | 59 | ```rust 60 | fn main() { 61 | let mut empty_string = String::new(); 62 | let empty_string_with_capacity = String::with_capacity(50); 63 | let string_from_bytestring: String = String::from_utf8(vec![82, 85, 83, 84]).expect("Creating String from bytestring failed"); 64 | 65 | println!("Length of the empty string is {}", empty_string.len()); 66 | println!("Length of the empty string with capacity is {}", empty_string_with_capacity.len()); 67 | println!("Length of the string from a bytestring is {}", string_from_bytestring.len()); 68 | 69 | println!("Bytestring says {}", string_from_bytestring); 70 | 71 | empty_string.push('1'); 72 | println!("{}", empty_string); 73 | 74 | empty_string.push_str("2345"); 75 | println!("{}", empty_string); 76 | 77 | println!("{}", empty_string.len()); 78 | } 79 | ``` 80 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/数据/字符串/字符编码.md: -------------------------------------------------------------------------------- 1 | # 字符编码 2 | 3 | ## 编码 4 | 5 | 如下图为字符 **编码** 和 **解码** 过程。 6 | 7 | ![](./encode.png) 8 | 9 | ### ASCII编码 10 | 11 | ASCII是7位编码,编码范围是0x00~0FF。ASCII自负集包括英文字母、阿拉伯数字和标点符号等字符。 12 | 13 | ### Unicode编码 14 | 15 | ASCII编码是7位编码,无法存储其它以外的语言字符,存储像中文这类字符只能使用其它编码。Unicode编码汇集了全球所有国家字符的编码,汇集成一个字符表。 16 | 17 | ### 码点 & 字符编码 18 | 19 | `Unicode编码`字符表保存字符和数字映射关系,该数字称为**码点**。码点保证了`Unicode`字符的唯一性,根据码点数量使用`ucs-2`(2个字节)或`ucs-4`(4个字节)两种方案,将码点存储到内存中。 20 | 21 | 直接将码点存储到内存/磁盘是一种浪费,可以使用一种UTF节约内存存储的方式将码点存储到内存中。 22 | 23 | `UCS`代表`Unicode`编码映射关系的码表;`UTF`将码表映射关系的数字存储到内存。即: **映射是码点;UTF是存储** 24 | 25 | 26 | ### 字符解码过程 27 | 28 | 字符的码点最终存储在内存中(ASCII 1字节; 中文 3~4字节)。为了显示,就需要**字库(Font)**,拿到要显示的码点,作为字库的索引,从中查找,然后通过GDI+将数据画到显示器上。 29 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/数据/指针/ptr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/数据/指针/ptr.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/数据/枚举/枚举.md: -------------------------------------------------------------------------------- 1 | # 枚举 2 | 3 | Rust 枚举类型像C那样,从0开始自增,或显示设置值。 4 | 5 | ```rust 6 | enum Letter { 7 | A, 8 | B, 9 | C = 10, 10 | D, 11 | } 12 | 13 | assert_eq!(Letter::A as i32, 0); 14 | assert_eq!(Letter::B as i32, 1); 15 | assert_eq!(Letter::C as i32, 11); 16 | ``` 17 | 18 |   19 |   20 | 21 | 每个成员(variant)都可以**关联**额外的数据。 22 | 23 | * 无关联 24 | * 单个值: `(T)` 25 | * 元组: `(T1, T2, ...)` 26 | * 结构体: `{name: T, ...}` 27 | 28 | ```rust 29 | #![allow(dead_code)] 30 | #![allow(unused_variables)] 31 | #![allow(unused_imports)] 32 | 33 | /************************************************/ 34 | 35 | #[derive(Debug)] 36 | enum Letter { 37 | A, 38 | B(i32), 39 | D{x: i32, y: i32}, 40 | C(i32, String), 41 | } 42 | 43 | fn main() { 44 | let d = Letter::D{x: 1, y: 2}; 45 | println!("{:?}", d); 46 | } 47 | ``` 48 | 49 | 查看`enum`内存布局 50 | 51 | ```x86asm 52 | (gdb) x/2xg &d 53 | 0x7fffffffe388: 0x0000000100000002 0x00007fff00000002 // 主机序(小端); 专成大端表示: 0x00000002 0x00000001 0x00000002 54 | 55 | (gdb) x/4xw &d 56 | 0x7fffffffe388: 0x00000002 0x00000001 0x00000002 0x00007fff // 内存布局: 类型(enum所属成员值) + 数据 57 | ``` 58 | 59 |   60 | 61 | > d内存布局: `[variant_value, x, y]`, 也就是 `[2, 1, 2]`。 62 | > 63 | > 当然,编译器会进行对齐处理。实际存储顺序会有所不同(如上所示)。 64 | 65 |   66 |   67 | 68 | 用`use`缩写。 69 | 70 | ```rust 71 | fn main() { 72 | use Letter::*; 73 | 74 | let d = D{x: 1, y: 2}; 75 | println!("{:?}", d); 76 | } 77 | ``` 78 | 79 |   80 |   81 | 82 | 用`match`、`if-let` 解构关联数据。 83 | 84 | ```rust 85 | enum Lettle { 86 | A(i32, i32), 87 | B{x: i32, y: i32}, 88 | } 89 | 90 | fn main() { 91 | let b = Lettle::B{ x: 11, y: 22}; 92 | 93 | match b { 94 | Lettle::A(x, y) => println!("{} {}", x, y); 95 | Lettle::B{x, y} => println!("{} {}", x, y); 96 | } 97 | 98 | if let Lettle::B{x, y} = b { 99 | println!("{} {}", x, y); 100 | } 101 | } 102 | ``` 103 | 104 |   105 | 106 | ### Option 107 | 108 | 有两个成员,要么`Some(value)`, 要么`None`空值。可用作函数可选参数(默认值),结构体可选字段等。 109 | 110 | ```rust 111 | fn main() { 112 | let x = Some(123); 113 | 114 | if let Some(v) = x { 115 | println!("{}", v); 116 | } 117 | 118 | match x { 119 | Some(v) => println!("{}", v); 120 | None => println!("None"); 121 | } 122 | } 123 | ``` 124 | 125 |   126 |   127 | 128 | ### Result 129 | 130 | 用于函数返回值,可恢复性错误处理。 131 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/测试/单元测试/单元测试.md: -------------------------------------------------------------------------------- 1 | # 单元测试 2 | 3 | 直接在源码文件内编写测试函数,并以 `#[test]` 标记。 4 | 5 | ```rust 6 | // add.rs 7 | 8 | fn add(x: i32, y: i32) -> i32 { 9 | x + y 10 | } 11 | 12 | 13 | #[test] 14 | fn add_test() { 15 | assert_eq!(add(1, 2), 3); // 用断言判断测试结果。 16 | } 17 | 18 | #[test] 19 | fn result_test() -> Result<(), &'static str> { // 以 Result 返回测试结果。 20 | if 2 + 2 == 4 { return Err("abc"); } 21 | Ok(()) 22 | } 23 | ``` 24 | 25 |   26 | 27 | 确保该模块直接或间接导入根模块。 28 | 29 | * `go test -- --ignored`: 测试被忽略的函数。 30 | * `go test `: 指定名称测试。(函数部分名,或 `my::add`这样的模块名) 31 | 32 | ```rust 33 | $> cargo test 34 | Compiling ddd v0.1.0 (/root/rs/ddd) 35 | Finished test [unoptimized + debuginfo] target(s) in 6.04s 36 | Running /root/rs/ddd/target/debug/deps/ddd-af3dc66fefca6c35 37 | 38 | running 2 tests 39 | test add_test ... ok 40 | test result_test ... ok 41 | 42 | test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s 43 | ``` 44 | 45 |   46 | 47 | ## 组织 48 | 49 | 或者组织一下,将该源码文件内所有测试函数放入专门模块。 50 | 51 | > 子模块可访问父模块私有成员。 52 | 53 |   54 | 55 | ```rust 56 | fn add(x: i32, y: i32) -> i32 { 57 | x + y 58 | } 59 | 60 | #[cfg(test)] 61 | mod tests{ 62 | use super::*; 63 | 64 | #[test] 65 | fn add_test() { 66 | assert_eq!(add(1, 2), 3); 67 | } 68 | } 69 | ``` 70 | 71 | ```rust 72 | $> cargo test 73 | Compiling ddd v0.1.0 (/root/rs/ddd) 74 | Finished test [unoptimized + debuginfo] target(s) in 5.89s 75 | Running /root/rs/ddd/target/debug/deps/ddd-af3dc66fefca6c35 76 | 77 | running 1 test 78 | test tests::add_test ... ok 79 | 80 | test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s 81 | ``` 82 | 83 |   84 | 85 | ## 注释 86 | 87 | 除测试函数外,还有一些专用注释。 88 | 89 | ```rust 90 | #[test] 91 | #[should_panic] // #[should_panic(expected = "abc")] 92 | fn abc_test() { 93 | abc(); 94 | } 95 | 96 | #[test] 97 | #[ignore] // cargo test -- --ignored 98 | fn ign_test() { 99 | } 100 | ``` 101 | 102 |   103 | 104 | ## 集成测试 105 | 106 | 继承测试(integration test)是外部测试,只能针对公开成员。 107 | 108 | * 确保测试目标是library。(可以与`main.rs`共存) 109 | * 确保要测试模块已导入 `lib.rs`。 110 | * 创建与 src 同级目录tests。 111 | * 创建测试文件,如 `my_add_test.rs`。 112 | 113 | 每个测试文件都被当作独立 crate 编译。 114 | 115 | ```rust 116 | $ tree 117 | . 118 | ├── Cargo.lock 119 | ├── Cargo.toml 120 | ├── src 121 | │ ├── lib.rs 122 | │ ├── main.rs 123 | │ ├── my 124 | │ │ └── add.rs 125 | │ └── my.rs 126 | └── tests 127 | └── my_add_test.rs 128 | ``` 129 | 130 | ```rust 131 | // src/lib.rs 132 | 133 | pub mod my; 134 | ``` 135 | 136 | ```rust 137 | // tests/my_add_test.rs 138 | 139 | use demo::my::add::*; 140 | 141 | #[test] 142 | fn add_test() { 143 | assert_eq!(add(1, 2), 3); 144 | } 145 | ``` 146 | 147 |   148 | 149 | [Cargo Targets](https://doc.rust-lang.org/cargo/reference/cargo-targets.html), [Testing](https://doc.rust-lang.org/1.7.0/book/testing.html) -------------------------------------------------------------------------------- /Rust学习笔记_基础/测试/基准测试/基准测试.md: -------------------------------------------------------------------------------- 1 | # 基准测试 2 | 3 | 官方基准测试库还是实验状态,使用前要先安装。 4 | 5 | 代码和单元测试类似。 6 | 7 | ```rust 8 | // lib.rs 9 | 10 | #![feature(test)] // 启用!!! 11 | extern crate test; 12 | 13 | mod add; 14 | ``` 15 | 16 | ```rust 17 | // add.rs 18 | 19 | fn add(x: i32, y: i32) -> i32 { 20 | x + y 21 | } 22 | 23 | #[cfg(test)] 24 | mod tests { 25 | use super::*; 26 | use test::Bencher; 27 | 28 | #[test] 29 | fn add_test() { 30 | assert_eq!(add(1, 2), 3); 31 | } 32 | 33 | #[bench] 34 | fn add_bench(b: &mut Bencher) { 35 | b.iter(|| add(1, 2)); 36 | } 37 | 38 | } 39 | ``` 40 | 41 |   42 | 43 | 命令行添加`+nightly`,否则会出错。 44 | 45 | ```rust 46 | $ cargo +nightly bench --lib 47 | 48 | running 2 tests 49 | test add::tests::add_test ... ignored 50 | test add::tests::add_bench ... bench: 0 ns/iter (+/- 0) 51 | 52 | test result: ok. 0 passed; 0 failed; 1 ignored; ... finished in 3.49s 53 | 54 | 55 | $ cargo +nightly test --lib 56 | 57 | running 2 tests 58 | test add::tests::add_bench ... ok 59 | test add::tests::add_test ... ok 60 | 61 | test result: ok. 2 passed; 0 failed; 0 ignored; ... finished in 0.00s 62 | ``` 63 | 64 |   65 | 66 | ## 集成测试 67 | 68 | 使用 `src` 同级的 benches 目录,每个文件都独立编译。 69 | 70 | ```rust 71 | $ tree 72 | . 73 | |-- Cargo.lock 74 | |-- Cargo.toml 75 | |-- benches 76 | | `-- add_test.rs 77 | `-- src 78 | |-- add.rs 79 | |-- lib.rs 80 | `-- main.rs 81 | ``` 82 | 83 | ```rust 84 | // src/lib.rs 85 | 86 | pub mod add; 87 | ``` 88 | 89 | ```rust 90 | // src/add.rs 91 | 92 | pub fn add(x: i32, y: i32) -> i32 { 93 | x + y 94 | } 95 | ``` 96 | 97 | ```rust 98 | // benchs/add_test.rs 99 | 100 | #![feature(test)] 101 | extern crate test; 102 | 103 | use eee::add::*; 104 | use test::Bencher; 105 | 106 | #[bench] 107 | fn add_bench(b: &mut Bencher) { 108 | b.iter(|| add(1, 2)); 109 | } 110 | ``` 111 | 112 | ```rust 113 | 114 | $ cargo +nightly bench 115 | Compiling eee v0.1.0 (/root/rs/eee) 116 | Finished bench [optimized] target(s) in 9.43s 117 | Running unittests (target/release/deps/eee-3e6381fe1f10ca0a) 118 | 119 | running 0 tests 120 | 121 | test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s 122 | 123 | Running unittests (target/release/deps/eee-f2a605acbd6dad91) 124 | 125 | running 0 tests 126 | 127 | test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s 128 | 129 | Running unittests (target/release/deps/add_test-97a3bfeb168b555b) 130 | 131 | running 1 test 132 | test add_bench ... bench: 1 ns/iter (+/- 0) 133 | 134 | test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in 0.75s 135 | ``` 136 | 137 |   138 | 139 | [Cargo Targets](https://doc.rust-lang.org/cargo/reference/cargo-targets.html), [Benchmark Tests](https://doc.rust-lang.org/1.7.0/book/benchmark-tests.html) -------------------------------------------------------------------------------- /Rust学习笔记_基础/类型/别名.md: -------------------------------------------------------------------------------- 1 | # 别名 2 | 3 | 别名不是新的类型实体,允许和原类型比较。 4 | 5 | 类型名使用UpperCameICase命名方式。 6 | 7 | 别名有助于上下文更易理解,如`type NanoSecond = u64`。 8 | 9 | 如此,可以将通用数据结构应用于不同场合,使其具备特定的含义。 10 | 11 | ``` 12 | type Data = String; 13 | 14 | type Point = (i64, i64); // tuple 15 | ``` 16 | 17 | ``` 18 | fn test(x: i32) { 19 | println!("{}", x); 20 | } 21 | 22 | fn main() { 23 | type Num = i32; 24 | let a: Num = 100; 25 | 26 | test(a); 27 | } 28 | ``` 29 | 30 | 31 | ### 别名作用 32 | 33 | 别名可以让程序员在特定的上下文中,具备更好的阅读能力。 34 | 35 | > 说明: 36 | > 37 | > 源代码是长期需要维护的,源代码的可阅读性、可维护性很重要的。 38 | > 39 | > Rust为了让程序提升内存安全和执行性能,Rust语言将其它语言Runtime责任,交由程序员进行负责。Rust复杂程度相比其它语言更加复杂, 40 | > 正因为这样,所以源代码可阅读性更加重要。别名也是提升源代码可阅读性的一种手段。 -------------------------------------------------------------------------------- /Rust学习笔记_基础/类型/常量.md: -------------------------------------------------------------------------------- 1 | # 常量 2 | 3 | 常量使用`const`定义,通常大写名字。 4 | 5 | 必须提供类型和编译期可计算值。 6 | 7 | ``` 8 | const X: i32 = 100; // 全局常量 9 | 10 | fn main() { 11 | { 12 | const X: &str = "abc"; // 局部常量 13 | println!("{}", X); 14 | } 15 | 16 | println!("{}", X); 17 | } 18 | ``` -------------------------------------------------------------------------------- /Rust学习笔记_基础/类型/类型转换/From和Into.md: -------------------------------------------------------------------------------- 1 | # From 和 Into 2 | 3 | 实现将一种类型转换为另一种类型,我们可用 `From` 和 `Into` 特征,一个类型只需要实现 `From` 特征,就能自动获得 `Into` 特征的实现。在标准库中有无数 `From` 的实现,规定原生类型及其他常见类型的转换功能。 4 | 5 | ```rust 6 | impl Into for T where U: From { 7 | fn into(self) -> U { 8 | U::from(self) 9 | } 10 | } 11 | ``` 12 | 13 |   14 | 15 | ## str 和 String类型转换 16 | 17 | ```rust 18 | fn main() { 19 | let s = "hello, rust!"; 20 | let s1 = String::from(s); 21 | 22 | println!("{}", s1); 23 | } 24 | ``` 25 | 26 | ```x86asm 27 | ; let s = "hello, rust!"; 28 | (gdb) ptype s 29 | type = struct &str { 30 | data_ptr: *mut u8, 31 | length: usize, 32 | } 33 | 34 | ; let s1 = String::from(s); 35 | (gdb) ptype s1 36 | type = struct alloc::string::String { 37 | vec: alloc::vec::Vec, 38 | } 39 | ``` 40 | 41 |   42 | 43 | ## From 44 | 45 | 使用From对自定义类型转换。 46 | 47 | ```rust 48 | use std::convert::From; 49 | 50 | #[derive(Debug)] 51 | struct Number { 52 | value: i32, 53 | } 54 | 55 | impl From for Number { 56 | fn from(item: i32) -> Self { 57 | Number { value: item } 58 | } 59 | } 60 | 61 | fn main() { 62 | let num = Number::from(30); 63 | println!("My number is {:?}", num); 64 | } 65 | ``` 66 | 67 | ```x86asm 68 | (gdb) ptype num 69 | type = struct ddd::Number { 70 | value: i32, 71 | } 72 | ``` 73 | 74 |   75 | 76 | ## Into 77 | 78 | 使用 `Into` 通常要求指明要转换到的类型,因为编译器大多数时候不能推断它。 79 | 80 | ```rust 81 | use std::convert::From; 82 | 83 | #[derive(Debug)] 84 | struct Number { 85 | value: i32, 86 | } 87 | 88 | impl From for Number { 89 | fn from(item: i32) -> Self { 90 | Number { value: item } 91 | } 92 | } 93 | 94 | fn main() { 95 | let int = 5; 96 | let num: Number = int.into(); 97 | 98 | println!("My number is {:?}", num); 99 | } 100 | ``` 101 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/类型/类型转换/ToString和FromStr.md: -------------------------------------------------------------------------------- 1 | # ToString 和 FromStr 2 | 3 | ## ToString 4 | 5 | 将其它类型转换成 `String` 类型,只需要实现那个类型的 `ToString` trait即可。 然而不要直接这么做,应该实现 `fmt::Display` trait,它会自动提供 `ToString`,并且还可以用来打印类型。 6 | 7 | ```rust 8 | use std::string::ToString; 9 | 10 | struct Circle { 11 | radius: i32 12 | } 13 | 14 | impl ToString for Circle { 15 | fn to_string(&self) -> String { 16 | format!("Circle of radius {:?}", self.radius) 17 | } 18 | } 19 | 20 | fn main() { 21 | let circle = Circle { radius: 6 }; 22 | println!("{}", circle.to_string()); 23 | } 24 | ``` 25 | 26 |   27 | 28 | ## 解析字符串 29 | 30 | 经常需要把字符串转成数字,可以使用 `parse` 函数。我们需要提供要转换到的类型,这可以通过不使用类型推断,或者用 `turbofish` 实现。 31 | 32 | 只要目标类型实现了 `FromStr` trait,就可以用 `parse` 把字符串转成目标类型。标准库已经有很多类型实现了 `FromStr`。如果要转换到用户定义类型,只要手动实现 `FromStr` 就行。 33 | 34 | ```rust 35 | fn main() { 36 | let parsed: i32 = "5".parse().unwrap(); 37 | let turbo_parsed = "10".parse::().unwrap(); 38 | 39 | let sum = parsed + turbo_parsed; 40 | println!{"Sum: {:?}", sum}; 41 | } 42 | ``` 43 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/类型/类型转换/TryFrom和TryInto.md: -------------------------------------------------------------------------------- 1 | # TryFrom 和 TryInto 2 | 3 | 类似于 `From` 和 `Into`,`TryFrom` 和 `TryInto` 是类型转换的通用 trait。不同的是 `From/Into` 的是,`TryFrom` 和 `TryInfo` trait用于易出错的转换,所以返回值是 `Result` 类型。 4 | 5 | ```rust 6 | use std::convert::TryFrom; 7 | use std::convert::TryInto; 8 | 9 | #[derive(Debug, PartialEq)] 10 | struct EvenNumber(i32); 11 | 12 | impl TryFrom for EvenNumber { 13 | type Error = (); 14 | 15 | fn try_from(value: i32) -> Result { 16 | if value % 2 == 0 { 17 | Ok(EvenNumber(value)) 18 | } else { 19 | Err(()) 20 | } 21 | } 22 | } 23 | 24 | fn main() { 25 | assert_eq!(EvenNumber::try_from(8), Ok(EvenNumber(8))); 26 | assert_eq!(EvenNumber::try_from(5), Err(())); 27 | 28 | let result: Result = 8i32.try_into(); 29 | assert_eq!(result, Ok(EvenNumber(8))); 30 | 31 | let result: Result = 5i32.try_into(); 32 | assert_eq!(result, Err(())); 33 | } 34 | ``` 35 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/表达式/控制流.md: -------------------------------------------------------------------------------- 1 | # 控制流 2 | 3 | 依据条件控制代码执行,实现逻辑分支或循环。 4 | 5 | ## 选择 6 | 7 | 条件必须是bool表达式,否则出错。不会隐式转换。 8 | 9 | ```rust 10 | fn main() { 11 | let x = 5; 12 | 13 | if x >= 5 { 14 | println!("x >= 5"); 15 | } else if x < 5 && x > 0 { 16 | println!("0 < x < 5"); 17 | } else { 18 | println!("x <= 0"); 19 | } 20 | } 21 | ``` 22 | 23 | ```rust 24 | fn main() { 25 | let x = 5; 26 | 27 | if x { 28 | // ^ expected `bool`, found integer 29 | println!("{:?}", x); 30 | } 31 | } 32 | ``` 33 | 34 | 实现类似三元运算符(?:)效果。注意,两个返回值类型必须相同。 35 | 36 | ```rust 37 | fn main() { 38 | let x = true; 39 | let _a = if x { 1 } else { 0 }; 40 | } 41 | ``` 42 | 43 | ```rust 44 | fn main() { 45 | let x = true; 46 | let _a = if x { 1 } else { "abc" }; 47 | // ^^^^^ expected integer, found `&str` 48 | } 49 | ``` 50 | 51 | ## 循环 52 | 53 | 三种循环: 54 | 55 | * loop:无限循环,直到手工跳出(break,return)。 56 | * while:条件循环。 57 | * for: 迭代。 58 | 59 | 在loop里可用break返回值,while内只跳出。 60 | 61 | ```rust 62 | fn main() { 63 | let x = loop { 64 | break 1; 65 | }; 66 | 67 | println!("{:?}", x); 68 | } 69 | ``` 70 | 71 |   72 | 73 | ```rust 74 | fn main() { 75 | let mut count = 3; 76 | while count > 0 { 77 | println!("{}", count); 78 | count -= 1; 79 | } 80 | } 81 | ``` 82 | 83 | 迭代常用语遍历数据集合。 84 | 85 | ```rust 86 | fn main() { 87 | for x in 1..=10 { 88 | println!("{}", x); 89 | } 90 | } 91 | ``` 92 | 93 |   94 | 95 | ```rust 96 | fn main() { 97 | for (i, j) in (5..10).enumerate() { 98 | println!("i = {} and j = {}", i, j); 99 | } 100 | } 101 | ``` 102 | 103 |   104 | 105 | 从迭代器(iterator)内遍历数据。 106 | 107 | ```rust 108 | fn main() { 109 | let data = [1, 2, 3, 4]; 110 | for d in data.iter() { 111 | println!("{:?}", d); 112 | } 113 | } 114 | ``` 115 | 116 | `&data`引用实现了迭代器对象`iter()`,`data`本身并没有实现`iter()`。 117 | 118 |   119 | 120 | ```rust 121 | fn main() { 122 | let data = [1, 2, 3, 4]; 123 | for d in &data { 124 | println!("{:?}", d); 125 | } 126 | } 127 | ``` 128 | 129 | ```rust 130 | fn main() { 131 | let data = [1, 2, 3, 4]; 132 | for d in data { 133 | ^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it 134 | println!("{:?}", d); 135 | } 136 | } 137 | ``` 138 | 139 |   140 | 141 | 可配合标签(label)在多层嵌套中跳出。 142 | 143 | ```rust 144 | fn main() { 145 | 'outer: for x in 0..10 { 146 | 'inner: for y in 0..10 { 147 | if x % 2 == 0 { 148 | continue 'outer; 149 | } 150 | 151 | if y > 2 { 152 | break 'inner; 153 | } 154 | 155 | println!("x: {}, y: {}", x, y); 156 | } 157 | } 158 | } 159 | ``` 160 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/表达式/迭代器.md: -------------------------------------------------------------------------------- 1 | # 迭代器 2 | 3 | 迭代器兼容任意普通类型,可以通过3种方式遍历集合类型中的元素: `self`、`&self` 及 `&mut self`。 4 | 5 | ```rust 6 | pub trait Iterator { 7 | // 迭代器产生的类型 8 | type Item; 9 | 10 | // 当需要从迭代的类型中读取一个值时,会调用next方法 11 | fn next(&mut self) -> Option; 12 | ``` 13 | 14 | 要让类型支持迭代,只需指定 `Item` 类型,并实现 `next` 方法。 15 | 16 |   17 | 18 | ## 生成迭代器 19 | 20 | 迭代器是为某些包装器类型是实现的,它通过所有权、可变、不可变引用来引用集合类型中的元素。将类型转换为迭代器的方法也遵循常规的命名规范: 21 | 22 | * `iter()`: 通过引用获取元素。 23 | * `iter_mut()`: 用于获取元素的可变引用。 24 | * `into_iter()`: 用于获取值的所有权,**并在完全迭代后使用实际类型,原始集合将无法再访问。** 25 | 26 |   27 | 28 | ## 自定义迭代器 29 | 30 | ```rust 31 | 32 | use std::usize; 33 | 34 | struct Primes { 35 | limit: usize 36 | } 37 | 38 | fn compute_primes(limit: usize) -> Vec { 39 | let mut sieve = vec![true; limit]; 40 | let m = 2; 41 | while m * m < limit { 42 | if sieve[m] { 43 | for i in (m * 2..limit).step_by(m) { 44 | sieve[i] = false; 45 | } 46 | } 47 | } 48 | sieve 49 | } 50 | 51 | impl Primes { 52 | fn iter(&self) -> PrimesIter { 53 | PrimesIter { 54 | index: 2, 55 | computed: compute_primes(self.limit) 56 | } 57 | } 58 | 59 | fn new(limit: usize) -> Primes { 60 | Primes { limit} 61 | } 62 | } 63 | 64 | struct PrimesIter { 65 | index: usize, 66 | computed: Vec 67 | } 68 | 69 | impl Iterator for PrimesIter { 70 | type Item = usize; 71 | 72 | fn next(&mut self) -> Option { 73 | loop { 74 | self.index += 1; 75 | if self.index > self.computed.len() - 1 { 76 | return None; 77 | } else if self.computed[self.index] { 78 | return Some(self.index); 79 | } else { 80 | continue 81 | } 82 | } 83 | } 84 | } 85 | 86 | fn main() { 87 | let primes = Primes::new(100); 88 | for i in primes.iter() { 89 | print!("{}, ", i); 90 | } 91 | } 92 | ``` 93 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/进阶/宏/宏.md: -------------------------------------------------------------------------------- 1 | # 宏 2 | 3 | 宏是一种元编程技术,用代码生成代码。不同于C的文本替换,Rust以抽象语法树(AST)展开。 4 | 5 | * 不同于函数,宏可直接展开到调用作用域内。 6 | * 生成代码,灵活性非泛型可比。 7 | * 不便于调试。 8 | 9 | ```rust 10 | macro_rules! say_hello{ 11 | () => ( 12 | println!("Hello"); 13 | ); 14 | } 15 | 16 | fn main() { 17 | say_hello!(); 18 | } 19 | ``` 20 | 21 |   22 | 23 | 添加参数,并标注其类型。 24 | 25 | > 参数以`$`为前缀,`ident`表明类型是标识符,比如函数或变量名。 26 | 27 | ```rust 28 | macro_rules! say_hello{ 29 | ($s: ident) => ( 30 | println!("hello, {}!", $s); 31 | ); 32 | } 33 | 34 | fn main() { 35 | let s = "world!"; 36 | 37 | say_hello!(s); 38 | } 39 | ``` 40 | 41 | ```rust 42 | macro_rules! create_add { 43 | ($name: ident, $type: ty) => ( 44 | fn $name(x: $type, y: $type) -> $type { 45 | x + y 46 | } 47 | ); 48 | } 49 | 50 | create_add!(add1, i32); 51 | create_add!(add2, f32); 52 | 53 | fn main() { 54 | add1(1, 2); 55 | add2(1.1, 1.2); 56 | } 57 | ``` 58 | 59 |   60 | 61 | 像 `match` 那样,分支匹配。 62 | 63 | ```rust 64 | macro_rules! test { 65 | ($one: expr) => ( 66 | println!("{:?}", $one); 67 | ); 68 | 69 | ($one: expr, $tow: expr) => ( 70 | println!("{:?}, {:?}", $one, $tow); 71 | ); 72 | } 73 | 74 | fn main() { 75 | test!(1+1); 76 | test!(1+1, 2); 77 | } 78 | ``` 79 | 80 |   81 | 82 | 接受变参,递归展开。 83 | 84 | ```rust 85 | macro_rules! test { 86 | ($one: expr) => ( 87 | println!("{:?}", $one); 88 | ); 89 | 90 | ($one: expr, $($two: expr),+) => ( // + 表示 1 到多个 91 | test!{ $one } // 递归调用,用大括号 92 | test!{ $($two),+ } 93 | ); 94 | } 95 | 96 | fn main() { 97 | test!(1 + 1); 98 | test!(1+2, 4, 3*4); 99 | } 100 | ``` 101 | 102 | [Macros](https://doc.rust-lang.org/1.7.0/book/macros.html) 103 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/进阶/注释/注释.md: -------------------------------------------------------------------------------- 1 | # 注释 2 | 3 | 注释(sttribute)是一种元数据标记,可用于`crate`、`module`,以及类型、函数等。 4 | 5 | * `#[name]`: 作用于下一项。 6 | * `#![name]`: 用于外部项(enclosing, crate)。 7 | 8 | * `#![feature]`: 启用实验性(unstable)功能。 9 | * `#![allow]`: 忽略警告。 10 | * `#[cfg]`: 条件编译(test,debug,arch,os)。 11 | * `#[inline]`: 函数内联。 12 | * `#[test]`: 单元测试。 13 | * `#[bench]`: 基准测试。 14 | 15 | ## 抑制警告 16 | 17 | 避免过多无害的编译提示,造成阅读障碍。 18 | 19 | ```rust 20 | #![allow(dead_code)] 21 | #![allow(unused_variables)] 22 | #![allow(unused_imports)] 23 | ``` 24 | 25 | ## 函数内联 26 | 27 | 向编译器提供函数内联建议。 28 | 29 | * `#[inline]` 30 | * `#[inline(always)]` 31 | * `#[inline(never)]` 32 | 33 | ```rust 34 | #[inline(always)] 35 | fn add(x: i32, y: i32) -> i32 { 36 | x + y 37 | } 38 | ``` 39 | 40 | ## 条件编译 41 | 42 | 按平台和架构等条件选择编译。 43 | 44 | ```rust 45 | #[cfg(debug_assertions)] 46 | fn test() { 47 | println!("debug"); 48 | } 49 | 50 | #[cfg(not(debug_assertions))] 51 | fn test() { 52 | println!("release"); 53 | } 54 | ``` 55 | 56 |   57 | 58 | [Attibutes](https://doc.rust-lang.org/reference/attributes.html) 59 | 60 | [Conditional compilation](https://doc.rust-lang.org/reference/conditional-compilation.html) 61 | 62 | [Procedural Macros](https://doc.rust-lang.org/reference/procedural-macros.html) -------------------------------------------------------------------------------- /Rust学习笔记_基础/错误/README.md: -------------------------------------------------------------------------------- 1 | # Error handling 2 | 3 | ## 参考资料 4 | 5 | * [Youbute](https://www.youtube.com/watch?v=rAF8mLI0naQ) -------------------------------------------------------------------------------- /Rust学习笔记_基础/错误/panic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/错误/panic.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/附录/imgs/ir.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/附录/imgs/ir.jpg -------------------------------------------------------------------------------- /Rust学习笔记_基础/附录/imgs/rust编译过程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/Rust学习笔记_基础/附录/imgs/rust编译过程.png -------------------------------------------------------------------------------- /Rust学习笔记_基础/附录/安装.md: -------------------------------------------------------------------------------- 1 | # 安装 2 | 3 | 最简单的方法是通过 `rustup` 安装。 4 | 5 | ```bash 6 | $> curl https://sh.rustup.rs -sSf | sh -s -- -y 7 | ``` 8 | 9 | ```bash 10 | The Rust toolchain installer 11 | 12 | USAGE: 13 | rustup [FLAGS] [+toolchain] 14 | 15 | SUBCOMMANDS: 16 | show Show the active and installed toolchains or profiles 17 | update Update Rust toolchains and rustup 18 | check Check for updates to Rust toolchains 19 | ``` 20 | 21 |   22 | 23 | > 工具链分 `stable`、`beta`、`nightly` 三个版本,可以 `rustup install` 安装。 24 | > 25 | > 随后,以 `cargo +nightly subcommand` 方式执行相关命令。 26 | 27 |   28 | 29 | 安装源码,以便调试定位。 30 | 31 | ```bash 32 | $> rustup component add rust-src 33 | $> rustc --print sysroot 34 | ``` 35 | 36 |   37 | 38 | ## 第三方工具 39 | 40 | 使用 `cargo install` 安装,子命令。 41 | 42 | * [cargo-cache](https://crates.io/crates/cargo-cache):缓存管理。 43 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/附录/版本.md: -------------------------------------------------------------------------------- 1 | # Rust 版本 2 | 3 | Rust有三个发布通道(release channel): 4 | 5 | * Nightly 6 | * Beta 7 | * Stable(稳定版) 8 | 9 | 大部分Rust开发者主要采用稳定版通道,不过希望实验新功能的开发者可能会使用nightly或beta版。 10 | 11 |   12 | 13 | ## rustup 和 rust nightly 的职责 14 | 15 | Rustup使得改变不同发布通道的Rust更为简单,在其全局或分项目的层次工作。默认会安装稳定版Rust。 16 | 17 | ```bash 18 | $> rustup install nightly 19 | ``` 20 | 21 | Rustup也安装了所有的工具链(toolchains),默认是稳定版。如果想切换到其它发布通道,则可以使用如下操作: 22 | 23 | ```bash 24 | $> rustup toolchain list 25 | stable-x86_64-unknown-linux-gnu (default) 26 | nightly-2020-07-01-x86_64-unknown-linux-gnu 27 | nightly-x86_64-unknown-linux-gnu 28 | 29 | $> cd ~/projects/needs-nightly 30 | $> rustup override set nightly 31 | ``` 32 | 33 | 现在,每次在 `~/projects/needs-nightly` 目录调用 `rustc` 或 `cargo`,`rustup`会确保使用nightly版Rust。 34 | -------------------------------------------------------------------------------- /Rust学习笔记_基础/附录/编译.md: -------------------------------------------------------------------------------- 1 | # 编译 2 | 3 | 直接使用 `rustc` 编译器,或使用 `cargo` 构建工具。 4 | 5 | ## 编译过程 6 | 7 | Rust编译过程主要有以下步骤: 8 | 9 | 源代码 -> 词法分析tokens -> 抽象语法树AST -> 高层中间语言HIR -> 中层中间语言MIR -> 底层语言虚拟机中间语言LLVM IR -> 机器码。 10 | 11 | ![编译过程](./imgs/rust编译过程.png) 12 | 13 |   14 | 15 | ### 词法分析 16 | 17 | * TokenStream:词法分析阶段,将文本语法中的元素识别为Rust编译器可以理解的词条。 18 | * AST:通过语法分析形成抽象语法树;进行`Desugaring`(脱糖处理)。 19 | 20 | ### 中间语言(IR) 21 | 22 | 词法分析之后,需要进行语义分析,Rust里面语义分析会持续到两层的中间语言(IR). `RFC 1211` 之前并不是两层中间语言,只有一层HIR中间语言。 23 | 24 | ![ir](./imgs/ir.jpg) 25 | 26 | * HIR:目前HIR主要是将AST进一步降级,方便编译器理解的一种高级中间语言。包括`rustc_typeck`,用于类型检查和类型推断。 27 | 28 | * THIR(`Typed High-Level Intermediate Representation`):它是在类型检查后生成的,它(截止2021/08)仅用于构造MIR和穷举检查,该IR具体实现是在MIR。该IR还提供一个 `unsafety` 检查器,它在THIR上运行,作为当前MIR `unsafety` 替代品,可以通过将 `-Z thir-unsafeck` 标志传递给 `rustc` 进行替代 MIR `unsafety`。 29 | 30 | * MIR:它是由HIR构建的,它是Rust的一种彻底简化的形式,用于对流信息的安全检查,尤其是借用检查器(`borrow checker`);优化代码和代码生成。 31 | 32 |   33 | 34 | ### cargo-inspect 35 | 36 | `cargo-inspect` 可以对rust源代码进行desugering(脱糖),并查看幕后发生的事情。 37 | 38 | ```bash 39 | # 目前beta版本还不支持,只能运行在nightly版本 40 | 41 | $> rustup install nightly # 安装nightly版本 42 | $> rustup component add rustfmt # 添加rustfmt 43 | $> cargo install cargo-inspect # 安装cargo-inspect 44 | 45 | $> cargo [+nightly] inspect main.rs # 进行desugering 46 | ``` 47 | 48 |   49 | 50 | ## rustc 51 | 52 | 编译器只接受 crate root 作为输入文件。 53 | 54 | ```bash 55 | $> rustc [OPTIONS] INPUT 56 | ``` 57 | 58 | * `--crate-type`: 编译类型。(lib, bin) 59 | * `--crate-name`: 60 | * `--edition`: 版本。 (2015, 2018) 61 | * `-g`: 生成调试信息 62 | * `-O`: `优化代码`。(`-C opt-level=2`) 63 | * `-o`: 输出文件名。 64 | * `-v`: 详细输出。 65 | 66 |   67 | 68 | > 优化等级: 69 | > 70 | > 0: 不优化 71 | > 72 | > 1: 基础优化 73 | > 74 | > 2: 标准优化 75 | > 76 | > 3: 深度优化(all) 77 | > 78 | > s: 优化尺寸(size) 79 | > 80 | > z: 优化尺寸,关闭循矢量化 81 | 82 |   83 | 84 | ## cargo 85 | 86 | 整合工具链,可完成如下工作: 87 | 88 | * 项目管理。 89 | * 源码编译。 90 | * 依赖管理。 91 | 92 | ```bash 93 | $ cargo [+toolchain] [OPTIONS] [SUBCOMMAND] 94 | ``` 95 | 96 | * `new`: 创建新包 97 | * `--bin`: 使用 `binray` 模版。 98 | * `--lib`: 使用 `library` 模版。 99 | * `--name`: 包名。(默认使用目标名) 100 | * `init`: 将现有目录初始化为包。 101 | 102 |   103 | 104 | * `check, c`: 分析并报告错误,不生成目标文件。 105 | * `run, r`: 运行包 106 | * `--bin `: 指定 bin 目标 107 | * `--package `: 指定 package 目标 108 | * `--release`: 发布版本 109 | 110 | * `build, b`: 编译 111 | * `-v`: 输出 rustc详细信息。 112 | * `--workspace`: 编译工作空间下的所有包。 113 | * `--exclude `: 编译时忽略指定包。 114 | * `--lib`: 仅编译library。 115 | * `--bins`: 编译所有binary。 116 | * `--release`: 变异优化过的发布版本。 117 | 118 | * `test, t`: 运行测试。 119 | * `bench`: 运行性能测试。 120 | * `clean`: 清除 target目录。 121 | * `doc`: 生成包和依赖文档。 122 | 123 |   124 | 125 | * `update`: 更新依赖项 126 | * `search`: 搜索包(crate.io) 127 | * `publish`: 发布包(crate.io) 128 | 129 |   130 | 131 | * `--verbose, -v`: 输出详情编译参数信息。 132 | 133 |   134 | 135 | [Rustc Book](https://doc.rust-lang.org/rustc/index.html) 136 | 137 | [Cargo Commands](https://doc.rust-lang.org/cargo/commands/index.html) 138 | 139 | [Cargo Profiles](https://doc.rust-lang.org/cargo/reference/profiles.html) -------------------------------------------------------------------------------- /Rust学习笔记_基础/附录/资源.md: -------------------------------------------------------------------------------- 1 | # 资源 2 | 3 | 电子书、文章及开源项目收集 4 | 5 | [The Rust Programming Language](https://doc.rust-lang.org/1.7.0/book/README.html) 6 | 7 | [the Rust Reference](https://doc.rust-lang.org/stable/reference/), [CN](https://minstrel1977.gitee.io/rust-reference/) 8 | 9 | [The Rust Standard Library](https://doc.rust-lang.org/std/index.html) 10 | 11 | [The Edition Guide](https://doc.rust-lang.org/edition-guide/index.html), [CN](https://rustwiki.org/zh-CN/edition-guide/introduction.html) 12 | 13 |   14 | 15 | [The Rust Programming Language,by Steve and Carol](https://rustwiki.org/zh-CN/edition-guide/introduction.html), [CN](https://kaisery.github.io/trpl-zh-cn/title-page.html) 16 | 17 | [Rust by Example](https://doc.rust-lang.org/rust-by-example/), [CN](https://rust-by-example.budshome.com/index.html) 18 | 19 |   20 | 21 | [Asynchronous Programming in Rust](https://rust-lang.github.io/async-book/) -------------------------------------------------------------------------------- /Rust学习笔记_库/Rust构建Web应用程序/hyper/hyper.md: -------------------------------------------------------------------------------- 1 | # hyper 2 | 3 | hyper软件包可以解析HTTP消息,并且具有优雅的设计、侧重于强类型的API。它被设计为原始HTTP请求类型安全的抽象,而不像常见的HTTP程序库那样:将所有内容描述为字符串。 4 | 5 | hyper将客户端和服务端功能拆分为单独的模块。客户端允许你使用可配置的请求主体、首部及其他底层配置来构建和发送HTTP请求。服务端允许你打开侦听套接字,并将请求处理程序附加给它。但是它不包括任何请求路由处理程序实现—— 这些留给Web框架处理。它只在构建更高级Web框架的基础软件包。它在底层使用相同的tokio和futures异步抽象。 6 | 7 | hyper的核心 `Service` 特征: 8 | 9 | ```rust 10 | pub trait Service { 11 | type ReqBody: Payload; 12 | type ResBody: Payload; 13 | type Error: Into>; 14 | type Future: Future, Error = self::Error>; 15 | 16 | fn call(&mut self, req: Request) -> self::Future; 17 | } 18 | ``` 19 | 20 | * `Service` 特征表示一种类型,它处理从任何客户端发送的HTTP请求,并返回Response响应,这是一个future。 21 | * 该特征需要实现 `call`,它接收一个泛型 `Body`上参数化的 `Request`,并结合解析为 `Response` 的 `future`,该 `Response`通过关联类型 `ResBody`进行参数化。我们不需要手工实现此特征,因为 hyper包含一系列可以为用户实现Service特征的工厂方法。 22 | 23 |   24 | 25 | ## hyper服务器端API —— 构建一个短网址服务 26 | 27 | 详见具体项目 28 | -------------------------------------------------------------------------------- /Rust学习笔记_库/Rust构建Web应用程序/hyper/hyperurl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hyperurl" 3 | version = "0.1.0" 4 | authors = [] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | hyper = "0.12.17" 11 | serde_json = "1.0.33" 12 | futures = "0.1.25" 13 | lazy_static = "1.2.0" 14 | rust-crypto = "0.2.36" 15 | log = "0.4" 16 | pretty_env_logger = "0.3" 17 | -------------------------------------------------------------------------------- /Rust学习笔记_库/Rust构建Web应用程序/hyper/hyperurl/src/main.rs: -------------------------------------------------------------------------------- 1 | use log::{info, error}; 2 | use std::env; 3 | 4 | use hyper::Server; 5 | use hyper::service::service_fn; 6 | 7 | use hyper::rt::{self, Future}; 8 | 9 | mod shortener; 10 | mod service; 11 | use crate::service::url_service; 12 | 13 | fn main() { 14 | env::set_var("RUST_LOG", "hyperurl=info"); 15 | pretty_env_logger::init(); 16 | 17 | let addr = "127.0.0.1:3002".parse().unwrap(); 18 | let server = Server::bind(&addr) 19 | .serve(|| service_fn(url_service)) 20 | .map_err(|e| error!("server error: {}", e)); 21 | info!("URL shortener listening on http://{}", addr); 22 | rt::run(server); 23 | } 24 | -------------------------------------------------------------------------------- /Rust学习笔记_库/Rust构建Web应用程序/hyper/hyperurl/src/service.rs: -------------------------------------------------------------------------------- 1 | use std::sync::RwLock; 2 | use std::collections::HashMap; 3 | use std::sync::{Arc}; 4 | use std::str; 5 | use hyper::Request; 6 | use hyper::{Body, Response}; 7 | use hyper::rt::{Future, Stream}; 8 | 9 | use lazy_static::lazy_static; 10 | 11 | use crate::shortener::shorten_url; 12 | 13 | type UrlDb = Arc>>; 14 | type BoxFut = Box, Error = hyper::Error> + Send>; 15 | 16 | lazy_static! { 17 | static ref SHORT_URLS: UrlDb = Arc::new(RwLock::new(HashMap::new())); 18 | } 19 | 20 | pub(crate) fn url_service(req: Request) -> BoxFut { 21 | let reply = req.into_body().concat2().map(move |chunk| { 22 | let c = chunk.iter().cloned().collect::>(); 23 | let url_to_shorten = str::from_utf8(&c).unwrap(); 24 | let shortened_url = shorten_url(url_to_shorten); 25 | SHORT_URLS.write().unwrap().insert(shortened_url, url_to_shorten.to_string()); 26 | let a = &*SHORT_URLS.read().unwrap(); 27 | Response::new(Body::from(format!("{:#?}", a))) 28 | }); 29 | Box::new(reply) 30 | } 31 | -------------------------------------------------------------------------------- /Rust学习笔记_库/Rust构建Web应用程序/hyper/hyperurl/src/shortener.rs: -------------------------------------------------------------------------------- 1 | use crypto::digest::Digest; 2 | use crypto::sha2::Sha256; 3 | 4 | pub(crate) fn shorten_url(url: &str) -> String { 5 | let mut sha = Sha256::new(); 6 | sha.input_str(url); 7 | let mut s = sha.result_str(); 8 | s.truncate(5); 9 | format!("https://u.rl/{}", s) 10 | } 11 | -------------------------------------------------------------------------------- /Rust学习笔记_库/Rust构建Web应用程序/hyper/shorten/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "shorten" 3 | version = "0.1.0" 4 | authors = [] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | quicli = "0.4" 11 | structopt = "0.2" 12 | reqwest = "0.9" 13 | serde = "1" 14 | -------------------------------------------------------------------------------- /Rust学习笔记_库/Rust构建Web应用程序/hyper/shorten/src/main.rs: -------------------------------------------------------------------------------- 1 | use quicli::prelude::*; 2 | use structopt::StructOpt; 3 | 4 | const CONN_ADDR: &str = "127.0.0.1:3002"; 5 | 6 | #[derive(Debug, StructOpt)] 7 | struct Cli { 8 | #[structopt(long = "url", short = "u")] 9 | url: String, 10 | 11 | #[structopt(flatten)] 12 | verbosity: Verbosity, 13 | } 14 | 15 | fn main() -> CliResult { 16 | let args = Cli::from_args(); 17 | println!("Shortening: {}", args.url); 18 | let client = reqwest::Client::new(); 19 | let mut res = client 20 | .post(&format!("http://{}/shorten", CONN_ADDR)) 21 | .body(args.url) 22 | .send()?; 23 | let a: String = res.text().unwrap(); 24 | println!("http://{}", a); 25 | Ok(()) 26 | } 27 | -------------------------------------------------------------------------------- /Rust学习笔记_库/Rust网络编程/README.md: -------------------------------------------------------------------------------- 1 | # Rust网络编程 2 | 3 | 在主流操作系统中,网络堆栈的传输层为开发者提供了一系列API,其名为套接字(socket)。它包括一组接口,用于在两个进程之间建立通信连接。套接字允许你在本地或远程两个进程之间传递数据,而无须开发者了解底层的网络协议。 4 | 5 | Socket API主要用于 TCP/IP 层。在这一层,我们创建的套接字按不同级别进行分类: 6 | 7 | * 协议:根据协议,我们可以有TCP套接字或UDP套接字。TCP是一种包含状态的流协议,提供能够以可靠的方式传递消息的能力,而UDP是一种无状态且不可靠的协议。 8 | 9 | * 通信类型:根据我们是与本地计算机还是远程计算机上的进程通信,可以使用互联网套接字或者UNIX域套接字。互联网套接字用于在远程计算机上的进程之间交换信息。它由IP地址和端口构成的元组表示。远程通信使用IP套接字;UNIX域套接字用于本地计算机上运行的进程之间的通信。 10 | 11 | * I/O模型:根据如何读取和写入套接字数据,我们可以创建两种套接字: 阻塞套接字和非阻塞套接字。 12 | 13 |   14 | 15 | ## Rust 网络编程 16 | 17 | Rust在标准库中为我们提供了 `net` 模块。 包含传输层的网络单元(TCP/UDP)。对于TCP通信,我们有 `TcpStream` 和 `TcpListener` 类型。对于UDP通信,我们有 `UdpSocket` 类型。`net` 模块还提供了用于正确表示 `v4` 和 `v6` 版本IP地址的数据类型。 18 | 19 | 应用程序为客户提供了服务的质量和效率。从技术角度来看,会涉及到套接字I/O模型的选择问题。 20 | 21 | 在阻塞和非阻塞套接字之间进行选择会改变其体系结构、编写代码的方式,以及如何扩展到客户端。阻塞套接字为用户提供了是同步I/O模型,而非阻塞套接字为用户提供的是异步是异步I/O模型。在实现Socket API的平台上,例如UNIX,默认情况下会在阻塞模式下创建套接字。这要求主流的网络堆栈上默认的I/O模型是同步模型。 22 | 23 | -------------------------------------------------------------------------------- /Rust学习笔记_库/Rust网络编程/异步网络IO.md: -------------------------------------------------------------------------------- 1 | # 异步网络IO 2 | 3 | 同步I/O模型可能是在给定时间内处理多个客户端的主要瓶颈,必须使用线程处理更多的客户端。为更好的方法来扩展,我们可以让套接字是非阻塞的,而不是应对套接字的阻塞性质。 4 | 5 | 对于非阻塞套接字,其上的任何读取、写入或者操作都会立刻返回,无论操作成功与否。没有客户端需要等待请求完成,而是稍后同志请求成功与否。与线程相比,异步I/O模型非常高效,但它增加了代码的复杂性。 6 | 7 | 在基于UNIX的平台上,套接字上的轮询机制是通过poll和select系统调用完成的。这些调用在所有UNIX操作系统上都是兼容的,除此之外,Linux还支持epoll API。在poll和select对每个请求的套接字运行for循环的情况下,epoll通过运行时 `O(1)`来同志用户的套接字事件。 8 | 9 |   10 | 11 | ## Rust中的异步抽象 12 | 13 | Rust提供了第三方软件包形式的便捷抽象,用于处理异步I/O。当处理非阻塞套接字和底层套接字轮询机制时,它为开发人员简化了大多数复杂状态机的处理。可供用户选择的两个底层抽象软件包是 `futures` 和 `mio`。 14 | 15 |   16 | 17 | ### mio 18 | 19 | mio提供了底层机制的高度抽象,他可以为大多数IO复用API提供跨平台、高效的接口。mio是一款底层软件包,它提供了一种为 socket 事件设置反应器的便捷方法。它和标准库类型相似,例如 `TcpStream`类型,不过默认情况下它是非阻塞的。 20 | 21 |   22 | 23 | ### futures 24 | 25 | mio 杂耍式的套接字轮询状态机用起来并不是很方便。为了提供可供应用程序开发人员使用的高级AP,提供了 future 软件包。 26 | 27 | futures软件包提供了一个 `Future` 核心trait,这是该软件包的核心组成部分。 28 | 29 | ```rust 30 | pub trait Future { 31 | // Future将解析的值 32 | type Item; 33 | 34 | // 操作失败时的错误类型 35 | type Error; 36 | 37 | // poll 指定了应该如何完成future过程 38 | fn poll(&mut self) -> Poll; 39 | } 40 | ``` 41 | 42 |   43 | 44 | `Future` 值自身不能构建异步应用程序,你需要将某种反应器和事件循环来推进future完成。`poll` 函数指定了应该如何完成future过程。future也可以由几件事情组合而成,从而一个接一个地链接起来。为了推进future,我们需要一个反应器和事件循环实现,这是由tokio软件包提供。 45 | 46 |   47 | 48 | ### tokio 49 | 50 | tokio整合了上述两种抽象,以及工作窃取调度程序、事件循环和计时器实现,它提供了一个运行时来驱动future完成。通过tokio框架,你可以生成多个future并让它们同时运行。 51 | 52 | tokio软件包在技术上是一种运行时,由一个线程池、事件循环,基于mio的I/O事件的反应器组成。 53 | 54 | 当future没有任何数据要解析,或者在 `TcpStream` 客户端读取正在等待到达套接字的数据时,它将返回NoReady状态。但是在执行此操作时,还需要向反应器注册感兴趣的内容,以便能够再次获知服务器的任何新数据。 55 | 56 | 当创建future时,无须执行任何其他操作。对于future定义的工作任务,必须提交给执行程序完成。在tokio中,任务是可以执行future的用户级线程。在poll方法的实现中,任务必须安排自己稍后执行轮询,以防相关工作停滞。为此,它必须将其任务处理程序传递给反应器线程。在Linux中,反应器是mio软件包。 57 | 58 |   59 | 60 | ### 构建异步Redis服务器 61 | 62 | 略 63 | -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/advanced_errors/advanced_errs1.rs: -------------------------------------------------------------------------------- 1 | use std::num::ParseIntError; 2 | use std::str::FromStr; 3 | 4 | #[derive(PartialEq, Debug)] 5 | enum CreationError { 6 | Negative, 7 | Zero, 8 | } 9 | 10 | #[derive(PartialEq, Debug)] 11 | enum ParsePosNonzeroError { 12 | Creation(CreationError), 13 | ParseInt(ParseIntError), 14 | } 15 | 16 | // 自定义类型转换 17 | impl From for ParsePosNonzeroError { 18 | fn from(e: CreationError) -> Self { 19 | ParsePosNonzeroError::Creation(e) 20 | } 21 | } 22 | 23 | impl From for ParsePosNonzeroError { 24 | fn from(e: ParseIntError) -> Self { 25 | ParsePosNonzeroError::ParseInt(e) 26 | } 27 | } 28 | 29 | impl FromStr for PositiveNonzeroInteger { 30 | type Err = ParsePosNonzeroError; 31 | fn from_str(s: &str) -> Result { 32 | let x: i64 = s.parse()?; 33 | Ok(PositiveNonzeroInteger::new(x)?) 34 | } 35 | } 36 | 37 | #[derive(PartialEq, Debug)] 38 | struct PositiveNonzeroInteger(u64); 39 | 40 | impl PositiveNonzeroInteger { 41 | fn new(value: i64) -> Result { 42 | match value { 43 | x if x < 0 => Err(CreationError::Negative), 44 | x if x == 0 => Err(CreationError::Zero), 45 | x => Ok(PositiveNonzeroInteger(x as u64)), 46 | } 47 | } 48 | } 49 | 50 | #[cfg(test)] 51 | mod test { 52 | use super::*; 53 | 54 | #[test] 55 | fn test_parse_error() { 56 | assert!(matches!( 57 | PositiveNonzeroInteger::from_str("not a number"), 58 | Err(ParsePosNonzeroError::ParseInt(_)) 59 | )); 60 | } 61 | 62 | #[test] 63 | fn test_negative() { 64 | assert_eq!( 65 | PositiveNonzeroInteger::from_str("-555"), 66 | Err(ParsePosNonzeroError::Creation(CreationError::Negative)) 67 | ); 68 | } 69 | 70 | #[test] 71 | fn test_zero() { 72 | assert_eq!( 73 | PositiveNonzeroInteger::from_str("0"), 74 | Err(ParsePosNonzeroError::Creation(CreationError::Zero)) 75 | ); 76 | } 77 | 78 | #[test] 79 | fn test_positive() { 80 | let x = PositiveNonzeroInteger::new(42); 81 | assert!(x.is_ok()); 82 | assert_eq!(PositiveNonzeroInteger::from_str("42"), Ok(x.unwrap())); 83 | } 84 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/clippy/README.md: -------------------------------------------------------------------------------- 1 | # clippy 2 | 3 | `clippy` 工具是一些列 `lint` 的集合,用于捕获常见错误和改进 `Rust` 代码。 4 | 5 | 如果要使用 `clippy` 工具,则应该安装 `Clippy`。如果没有,则需要通过手动安装它: 6 | 7 | ```bash 8 | $> rustup component add clippy 9 | ``` 10 | 11 | 对任何 Cargo项目运行 `clippy`的lint: 12 | 13 | ```bash 14 | $> cargo clippy 15 | ``` 16 | 17 |   18 | 19 | ## Further information 20 | 21 | * [Github Repository](https://github.com/rust-lang/rust-clippy) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/clippy/clippy1.rs: -------------------------------------------------------------------------------- 1 | fn approx_equal(a: f64, b: f64, decimal_places: u8) -> bool { 2 | let factor = 10.0f64.powi(decimal_places as i32); 3 | let a = (a * factor).trunc(); 4 | let b = (b * factor).trunc(); 5 | a == b 6 | } 7 | 8 | fn main() { 9 | let x = 1.2331f64; 10 | let y = 1.2332f64; 11 | if !approx_equal(x, y, 4) { 12 | println!("Success"); 13 | } 14 | } 15 | 16 | /* 17 | // clippy check 18 | 19 | root@8d75790f92f5:~/rs/ddd/src# cargo clippy 20 | Finished dev [unoptimized + debuginfo] target(s) in 0.03s 21 | */ -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/clippy/clippy2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut res = 42; 3 | let option = Some(12); 4 | if let Some(x) = option { 5 | res += x 6 | } 7 | 8 | println!("{}", res); 9 | } 10 | 11 | /* 12 | // clippy check 13 | 14 | root@8d75790f92f5:~/rs/ddd/src# cargo clippy 15 | Checking ddd v0.1.0 (/root/rs/ddd) 16 | Finished dev [unoptimized + debuginfo] target(s) in 0.15s 17 | */ -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/collections/README.md: -------------------------------------------------------------------------------- 1 | # collections 2 | 3 | ## HashMap 4 | 5 | 检查两个`HashMap`是否具有相同的key/value. 6 | 7 | ```rust 8 | // 1. 使用Iterator::all会大大缩短代码 9 | // 2. 使用HashMap::contains_key优于检查的结果HashMap::get 10 | // 3. 首先检查长度,因为这是一种最高效的测试,应首先进行 11 | 12 | fn keys_match(map1: &HashMap, map2: &HashMap) -> bool { 13 | map1.len() == map2.len() && map1.keys().all(|k| map2.contains_key(k)) 14 | } 15 | ``` 16 | 17 |   18 | 19 | ## vec 20 | 21 | 如下是 `vec!` 的具体实现(简化版本): 22 | 23 | ```rust 24 | // macro_rules! 定义了名字vec后面跟上大括号 25 | // ( $( $x:expr ), *), 这是一个模式(pattern),如果模式匹配了后面相关的代码就会执行; 紧随逗号之后的,说明该模式匹配零个或者多个之前的任何模式 26 | // vec![1, 2, 3]; 调用宏时,$x模式与三个表达式1、2和 3进行了3次匹配 27 | #[macro_export] 28 | macro_rules! vec { 29 | ( $( $x:expr ), *) => { 30 | let mut temp_vec = Vec::new(); 31 | $( 32 | temp_vec.push($x); 33 | )* 34 | temp_vec 35 | }; 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/collections/hashmap1.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | fn fruit_basket() -> HashMap { 4 | // 创建一个空HashMap 5 | let mut basket = HashMap::new(); 6 | 7 | // 向HashMap插入K/V对 8 | basket.insert(String::from("banana"), 2); 9 | basket.insert(String::from("apple"), 2); 10 | basket.insert(String::from("orange"), 2); 11 | 12 | basket 13 | } 14 | 15 | #[cfg(test)] 16 | mod tests { 17 | // 引入当前模块(mod)的父模块所有资源 18 | use super::*; 19 | 20 | #[test] 21 | fn at_least_three_types_of_fruits() { 22 | let basket = fruit_basket(); 23 | // basket.len() 返回HashMap内元素数 24 | assert!(basket.len() >= 3); 25 | } 26 | 27 | #[test] 28 | fn at_least_five_fruits() { 29 | let basket = fruit_basket(); 30 | 31 | // basket.values() 返回HashMap元素的迭代器, 32 | // sum::() 获取迭代器值 33 | assert!(basket.values().sum::() >= 5); 34 | } 35 | } 36 | 37 | /* 38 | 数据结构: 39 | 40 | type = struct std::collections::hash::map::HashMap { 41 | base: hashbrown::map::HashMap, 42 | } 43 | 44 | 内存布局: 45 | 46 | basket = std::collections::hash::map::HashMap { 47 | base: hashbrown::map::HashMap { 48 | hash_builder: std::collections::hash::map::RandomState { 49 | k0: 17202417722039394206, 50 | k1: 10650482839738393711 51 | }, 52 | table: hashbrown::raw::RawTable<(alloc::string::String, i32)> { 53 | bucket_mask: 3, 54 | ctrl: core::ptr::non_null::NonNull { 55 | pointer: 0x5555555adaa0 "\377(Q ", '\377' , "(Q \000" 56 | }, 57 | growth_left: 0, 58 | items: 3, 59 | marker: core::marker::PhantomData<(alloc::string::String, i32)> 60 | } 61 | } 62 | } 63 | */ -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/collections/hashmap2.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | #[derive(Hash, PartialEq, Eq, Debug)] 4 | enum Fruit { 5 | Apple, 6 | Banana, 7 | Mango, 8 | Lychee, 9 | Pineapple, 10 | } 11 | 12 | fn fruit_basket(basket: &mut HashMap) { 13 | let fruit_kinds = vec![ 14 | Fruit::Apple, 15 | Fruit::Banana, 16 | Fruit::Mango, 17 | Fruit::Lychee, 18 | Fruit::Pineapple, 19 | ]; 20 | 21 | for fruit in fruit_kinds { 22 | // contains_key 判断HashMap是否包含该key 23 | if !basket.contains_key(&fruit) { 24 | basket.insert(fruit, 4); 25 | } 26 | } 27 | 28 | // 此处无法再访问fruit_kinds !!! 29 | // 1. 迭代vec后,将无法再次使用该vec 30 | // 2. 如果想继续使用,则循环遍历 &vec,而不是vec 31 | // for fruit in &fruit_kinds { 32 | // .... 33 | // } 34 | } 35 | 36 | #[cfg(test)] 37 | mod tests { 38 | use super::*; 39 | 40 | fn get_fruit_basket() -> HashMap { 41 | let mut basket = HashMap::::new(); 42 | basket.insert(Fruit::Apple, 4); 43 | basket.insert(Fruit::Mango, 2); 44 | basket.insert(Fruit::Lychee, 5); 45 | 46 | basket 47 | } 48 | 49 | #[test] 50 | fn test_given_fruits_are_not_modified() { 51 | let mut basket = get_fruit_basket(); 52 | fruit_basket(&mut basket); 53 | assert_eq!(*basket.get(&Fruit::Apple).unwrap(), 4); 54 | assert_eq!(*basket.get(&Fruit::Mango).unwrap(), 2); 55 | assert_eq!(*basket.get(&Fruit::Lychee).unwrap(), 5); 56 | } 57 | 58 | #[test] 59 | fn test_least_five_types_of_fruits() { 60 | let mut basket = get_fruit_basket(); 61 | fruit_basket(&mut basket); 62 | let count_fruit_kinds = basket.len(); 63 | assert!(count_fruit_kinds >= 5); 64 | } 65 | 66 | #[test] 67 | fn greater_than_eleven_fruits() { 68 | let mut basket = get_fruit_basket(); 69 | fruit_basket(&mut basket); 70 | let count = basket.values().sum::(); 71 | assert!(count > 11); 72 | } 73 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/collections/vec1.rs: -------------------------------------------------------------------------------- 1 | fn array_and_vec() -> ([i32; 4], Vec) { 2 | let a = [10, 20, 30, 40]; 3 | let v = vec![10, 20, 30, 40]; 4 | 5 | (a, v) 6 | } 7 | 8 | #[cfg(test)] 9 | mod tests { 10 | use super::*; 11 | 12 | #[test] 13 | fn test_array_and_vec_similarity() { 14 | let (a, v) = array_and_vec(); 15 | assert_eq!(a, v[..]); // 断言,两个值是否相等 16 | } 17 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/collections/vec2.rs: -------------------------------------------------------------------------------- 1 | fn vec_loop(mut v: Vec) -> Vec { 2 | // iter_mut: 返回一个允许修改的迭代器 3 | for i in v.iter_mut() { 4 | *i = *i*2; 5 | } 6 | v 7 | } 8 | 9 | #[cfg(test)] 10 | mod tests { 11 | use super::*; 12 | 13 | #[test] 14 | fn test_vec_looop() { 15 | // filter: 创建一个迭代器 16 | // take: 元素个数限制 17 | // collect: 将迭代器转换成集合 18 | let v: Vec = (1..).filter(|x| x%2 == 0).take(5).collect(); 19 | let ans = vec_loop(v.clone()); 20 | 21 | assert_eq!(ans, v.iter().map(|x| x*2).collect::>()); 22 | } 23 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/conversions/README.md: -------------------------------------------------------------------------------- 1 | # 类型转换 2 | 3 | Rust提供了很多将给定类型的值转换为另一种类型的方法。 4 | 5 | 最简单的类型转换形式是类型转换表达式,可以使用二元运算符进行表达。例如, `println("{}", 1 + 1.0);` 不能编译,因为 `1` 是整数,而 `1.0` 是浮点数。但是,`println!("{}", 1 as f32 + 1.0);` 可以通过编译。详情查看: [using_as](https://github.com/xuesongbj/Rust-Notes/blob/main/Rust%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0_%E5%BA%93_2021/exercises/conversions/using_as.rs)。 6 | 7 | Rust还提供了类型转换特征。这些特征可以在 `convert` 模块下找到: 8 | 9 | * `From` 和 `Into` 转换:[from_into](https://github.com/xuesongbj/Rust-Notes/blob/main/Rust%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0_%E5%BA%93_2021/exercises/conversions/from_into.rs) 10 | * `TryFrom` 和 `TryInto` 转换:[try_from_into](https://github.com/xuesongbj/Rust-Notes/blob/main/Rust%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0_%E5%BA%93_2021/exercises/conversions/try_from_into.rs) 11 | * `AsRef` 和 `AsMut` 转换:[as_ref_mut](https://github.com/xuesongbj/Rust-Notes/blob/main/Rust%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0_%E5%BA%93_2021/exercises/conversions/as_ref_mut.rs) 12 | 13 | 此外,`std::str` 模块提供了一个 `FromStr` 特征,它有助于通过字符串 `parse` 方法将字符串转换为目标类型。 如果对给定的类型 `Person` 正确实现,那么让 `p: Person = "Mark,20".parse().unwrap()` 应该在编译器和运行时 不会出现panic。 14 | 15 | 这些应该是标准库中将数据转换为所需类型的主要方法。 16 | 17 |   18 | 19 | ## 更多信息 20 | 21 | 更多信息请查阅标准库文档。 22 | 23 | * [conversions](https://doc.rust-lang.org/std/convert/index.html) 24 | * [FromStr](https://doc.rust-lang.org/std/str/trait.FromStr.html) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/conversions/as_ref_mut.rs: -------------------------------------------------------------------------------- 1 | fn byte_counter>(arg: T) -> usize { // >: 对函数参数的约束 2 | arg.as_ref().as_bytes().len() 3 | } 4 | 5 | fn char_counter>(arg: T) -> usize { 6 | arg.as_ref().chars().count() 7 | } 8 | 9 | fn main() { 10 | let s = "Café au lai"; 11 | println!("{}", char_counter(s)); 12 | println!("{}", byte_counter(s)); 13 | } 14 | 15 | #[cfg(test)] 16 | mod tests { 17 | use super::*; 18 | 19 | #[test] 20 | fn different_counts() { 21 | let s = "Café au lait"; 22 | assert_ne!(char_counter(s), byte_counter(s)); 23 | } 24 | 25 | #[test] 26 | fn same_counts() { 27 | let s = "Cafe au lait"; 28 | assert_eq!(char_counter(s), byte_counter(s)); 29 | } 30 | 31 | #[test] 32 | fn different_counts_using_string() { 33 | let s = String::from("Café au lait"); 34 | assert_ne!(char_counter(s.clone()), byte_counter(s)); 35 | } 36 | 37 | #[test] 38 | fn same_counts_using_string() { 39 | let s = String::from("Cafe au lait"); 40 | assert_eq!(char_counter(s.clone()), byte_counter(s)); 41 | } 42 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/conversions/using_as.rs: -------------------------------------------------------------------------------- 1 | fn average(values: &[f64]) -> f64 { 2 | let total = values.iter().fold(0.0, |a, b| a + b); 3 | total / (values.len() as f64) 4 | } 5 | 6 | fn main() { 7 | let values = [3.5, 0.3, 13.0, 11.7]; 8 | println!("{}", average(&values)); 9 | } 10 | 11 | #[cfg(test)] 12 | mod tests { 13 | use super::*; 14 | 15 | #[test] 16 | fn returns_proper_type_and_value() { 17 | assert_eq!(average(&[3.5, 0.3, 13.0, 11.7]), 7.125); 18 | } 19 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/enums/README.md: -------------------------------------------------------------------------------- 1 | # Enums 2 | 3 | Enums(枚举)是很多语言的一个特性,但它们的功能在每种语言都不同。Rust的枚举类似于函数式语言中的代数数据类型,与枚举结合使用的是Rust的"模式匹配",它可以轻松地为枚举的不同值运行不同的代码。 4 | 5 | &bsp; 6 | 7 | ## Further information 8 | 9 | * [Enums](https://doc.rust-lang.org/book/ch06-00-enums.html) 10 | * [Pattern syntax](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/enums/enums1.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | enum Message { 3 | Quit, 4 | Echo, 5 | Move, 6 | ChangeColor, 7 | } 8 | 9 | fn main() { 10 | println!("{:?}", Message::Quit); 11 | println!("{:?}", Message::Echo); 12 | println!("{:?}", Message::Move); 13 | println!("{:?}", Message::ChangeColor); 14 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/enums/enums2.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | enum Message { 3 | Move {x: i32, y: i32}, // struct{} 4 | Echo(String), // function(){} 5 | ChangeColor(i32, i32, i32), // tuple 6 | Quit, // int 7 | } 8 | 9 | impl Message { 10 | fn call(&self) { 11 | println!("{:?}", &self); 12 | } 13 | } 14 | 15 | fn main() { 16 | let messages = [ 17 | Message::Move{x: 10, y: 30}, 18 | Message::Echo(String::from("hello world")), 19 | Message::ChangeColor(255, 255, 255), 20 | Message::Quit, 21 | ]; 22 | 23 | for message in &messages { 24 | message.call(); 25 | } 26 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/enums/enums3.rs: -------------------------------------------------------------------------------- 1 | enum Message { 2 | Move(Point), // Point struct 3 | Echo(String), // String 4 | ChangeColor((u8, u8, u8)), // tuple 5 | Quit, // bool 6 | } 7 | 8 | struct Point { 9 | x: u8, 10 | y: u8, 11 | } 12 | 13 | struct State { 14 | color: (u8, u8, u8), 15 | position: Point, 16 | quit: bool, 17 | } 18 | 19 | impl State { 20 | fn change_color(&mut self, color: (u8, u8, u8)) { 21 | self.color = color; 22 | } 23 | 24 | fn quit(&mut self) { 25 | self.quit = true; 26 | } 27 | 28 | fn echo(&self, s: String) { 29 | println!("{}", s); 30 | } 31 | 32 | fn move_position(&mut self, p: Point) { 33 | self.position = p; 34 | } 35 | 36 | fn process(&mut self, message: Message) { 37 | match message { 38 | Message::ChangeColor(color) => self.change_color(color), 39 | Message::Echo(s) => self.echo(s), 40 | Message::Move(p) => self.move_position(p), 41 | Message::Quit => self.quit(), 42 | } 43 | } 44 | } 45 | 46 | #[cfg(test)] 47 | mod tests { 48 | use super::*; 49 | 50 | #[test] 51 | fn test_match_message_call() { 52 | let mut state = State { 53 | quit: false, 54 | position: Point { x: 0, y: 0}, 55 | color: (0, 0, 0), 56 | }; 57 | 58 | state.process(Message::ChangeColor((255, 0, 255))); 59 | state.process(Message::Echo(String::from("hello world"))); 60 | state.process(Message::Move(Point{x:10, y: 15})); 61 | state.process(Message::Quit); 62 | 63 | assert_eq!(state.color, (255, 0, 255)); 64 | assert_eq!(state.position.x, 10); 65 | assert_eq!(state.position.y, 15); 66 | assert_eq!(state.quit, true); 67 | } 68 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/error_handling/README.md: -------------------------------------------------------------------------------- 1 | # Error handling 2 | 3 | 大多数错误都没有严重到需要程序完全停止的程度。有时,当一个函数失败时,可以进行处理或者退出函数。例如,如果打开一个文件并且该文件不存在而失败,你可能希望创建该文件而不是终止该进程。 4 | 5 |   6 | 7 | ## Further information 8 | 9 | * [Error Handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html) 10 | * [Generic](https://doc.rust-lang.org/book/ch10-01-syntax.html) 11 | * [Result](https://doc.rust-lang.org/rust-by-example/error/result.html) 12 | * [Boxing errors](https://doc.rust-lang.org/rust-by-example/error/multiple_error_types/boxing_errors.html) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/error_handling/errors1.rs: -------------------------------------------------------------------------------- 1 | pub fn generate_nametag_text(name: String) -> Option { 2 | if name.len() > 0 { 3 | Some(format!("Hi! My name is {}", name)) 4 | } else { 5 | None 6 | } 7 | } 8 | 9 | 10 | #[cfg(test)] 11 | mod tests { 12 | use super::*; 13 | 14 | #[test] 15 | fn generates_nametag_text_for_a_nonempty_name() { 16 | assert_eq!( 17 | generate_nametag_text("Beyoncé".into()), 18 | Some("Hi! My name is Beyoncé".into()) 19 | ); 20 | } 21 | 22 | #[test] 23 | fn explains_why_generating_nametag_text_fails() { 24 | assert_eq!( 25 | generate_nametag_text("".into()), 26 | None 27 | ); 28 | } 29 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/error_handling/errors2.rs: -------------------------------------------------------------------------------- 1 | use std::num::ParseIntError; 2 | 3 | pub fn total_cost(item_quantity: &str) -> Result { 4 | let processing_fee = 1; 5 | let cost_per_item = 5; 6 | 7 | // {String}.parse::(): 将字符串转换成i32类型 8 | let qty = item_quantity.parse::()?; // 返回i32类型值或者返回Err错误 9 | 10 | Ok(qty * cost_per_item + processing_fee) 11 | } 12 | 13 | #[cfg(test)] 14 | mod tests { 15 | use super::*; 16 | 17 | #[test] 18 | fn item_quantity_is_a_valid_number() { 19 | assert_eq!(total_cost("34"), Ok(171)); 20 | } 21 | 22 | #[test] 23 | fn item_quantity_is_an_invalid_number() { 24 | assert_eq!( 25 | total_cost("beep boop").unwrap_err().to_string(), 26 | "invalid digit found in string" 27 | ); 28 | } 29 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/error_handling/errors3.rs: -------------------------------------------------------------------------------- 1 | use std::num::ParseIntError; 2 | 3 | fn main() -> Result<(), ParseIntError>{ 4 | let mut tokens = 100; 5 | let pretend_user_input = "8"; 6 | let cost = total_cost(pretend_user_input)?; // `?`运算符只能用在返回`Result` 或 `Option` 的函数中 7 | 8 | if cost > tokens { 9 | println!("You can't afford that many!"); 10 | } else { 11 | tokens -= cost; 12 | println!("You now have {} tokens.", tokens); 13 | } 14 | 15 | Ok(()) 16 | } 17 | 18 | pub fn total_cost(item_quantity: &str) -> Result { 19 | let processing_fee = 1; 20 | let cost_per_item = 5; 21 | let qty = item_quantity.parse::()?; 22 | 23 | Ok(qty * cost_per_item + processing_fee) 24 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/error_handling/errors4.rs: -------------------------------------------------------------------------------- 1 | #[derive(PartialEq, Debug)] 2 | struct PositiveNonzeroInteger(u64); 3 | 4 | #[derive(PartialEq, Debug)] 5 | enum CreationError { 6 | Negative, 7 | Zero, 8 | } 9 | 10 | impl PositiveNonzeroInteger { 11 | fn new(value: i64) -> Result { 12 | if value == 0 { 13 | Err(CreationError::Zero) 14 | } else if value < 0 { 15 | Err(CreationError::Negative) 16 | } else { 17 | Ok(PositiveNonzeroInteger(value as u64)) 18 | } 19 | } 20 | } 21 | 22 | #[test] 23 | fn test_creation() { 24 | assert!(PositiveNonzeroInteger::new(10).is_ok()); 25 | assert_eq!( 26 | Err(CreationError::Negative), 27 | PositiveNonzeroInteger::new(-10) 28 | ); 29 | assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0)); 30 | 31 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/error_handling/errors5.rs: -------------------------------------------------------------------------------- 1 | use std::error; 2 | use std::fmt; 3 | 4 | type MainResult = std::result::Result>; 5 | 6 | fn main() -> MainResult<()> { 7 | let pretend_user_input = "42"; 8 | let x: i64 = pretend_user_input.parse()?; 9 | println!("output={:?}", PositiveNonzeroInteger::new(x)?); 10 | Ok(()) 11 | } 12 | 13 | #[derive(PartialEq, Debug)] 14 | struct PositiveNonzeroInteger(u64); 15 | 16 | #[derive(PartialEq, Debug)] 17 | enum CreationError { 18 | Negative, 19 | Zero, 20 | } 21 | 22 | impl PositiveNonzeroInteger { 23 | fn new(value: i64) -> Result { 24 | match value { 25 | x if x < 0 => Err(CreationError::Negative), 26 | x if x == 0 => Err(CreationError::Zero), 27 | x => Ok(PositiveNonzeroInteger(x as u64)) 28 | } 29 | } 30 | } 31 | 32 | impl fmt::Display for CreationError { 33 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 34 | let description = match *self { 35 | CreationError::Negative => "number is negative", 36 | CreationError::Zero => "number is zero", 37 | }; 38 | f.write_str(description) 39 | } 40 | } 41 | 42 | impl error::Error for CreationError { 43 | fn description(&self) -> &str { 44 | match *self { 45 | CreationError::Negative => "Negative", 46 | CreationError::Zero => "Zero", 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/error_handling/errors6.rs: -------------------------------------------------------------------------------- 1 | use std::num::ParseIntError; 2 | 3 | #[derive(PartialEq, Debug)] 4 | enum ParsePosNonzeroError { 5 | Creation(CreationError), 6 | ParseInt(ParseIntError) 7 | } 8 | 9 | impl ParsePosNonzeroError { 10 | fn from_creation(err: CreationError) -> ParsePosNonzeroError { 11 | ParsePosNonzeroError::Creation(err) 12 | } 13 | 14 | fn from_parsing(err: ParseIntError) -> ParsePosNonzeroError { 15 | ParsePosNonzeroError::ParseInt(err) 16 | } 17 | } 18 | 19 | fn parse_pos_nonzero(s: &str) -> Result { 20 | let x = s.parse().map_err(ParsePosNonzeroError::from_parsing)?; 21 | PositiveNonzeroInteger::new(x).map_err(ParsePosNonzeroError::from_creation) 22 | } 23 | 24 | /* 25 | Option II: 26 | 27 | fn parse_pos_nonzero(s: &str) -> Result { 28 | // s.parse() : 字符串转换成另外一种类型 29 | // map_err() : 当值为 `Err(E)` 时,调用作为参数的函数处理错误 30 | let x = match s.parse() { 31 | Ok(i) => i, 32 | Err(e) => return Err(ParsePosNonzeroError::from_parsing(e)), 33 | }; 34 | PositiveNonzeroInteger::new(x).map_err(ParsePosNonzeroError::from_creation) 35 | } 36 | */ 37 | 38 | /* 39 | Option III: 40 | 41 | fn parse_pos_nonzero(s: &str) -> Result { 42 | // and_then : 如果没有异常,则执行and_then参数的函数,否则返回 ParsePosNonzeroError::from_parsing 错误 43 | s.parse() 44 | .map_err(ParsePosNonzeroError::from_parsing) 45 | .and_then(|x| { 46 | PositiveNonzeroInteger::new(x) 47 | .map_err(ParsePosNonzeroError::from_creation) 48 | }) 49 | } 50 | */ 51 | 52 | #[derive(PartialEq, Debug)] 53 | struct PositiveNonzeroInteger(u64); 54 | 55 | #[derive(PartialEq, Debug)] 56 | enum CreationError { 57 | Negative, 58 | Zero, 59 | } 60 | 61 | impl PositiveNonzeroInteger { 62 | fn new(value: i64) -> Result { 63 | match value { 64 | x if x < 0 => Err(CreationError::Negative), 65 | x if x == 0 => Err(CreationError::Zero), 66 | x => Ok(PositiveNonzeroInteger(x as u64)) 67 | } 68 | } 69 | } 70 | 71 | #[cfg(test)] 72 | mod test { 73 | use super::*; 74 | 75 | #[test] 76 | fn test_parse_error() { 77 | assert!(matches!( 78 | parse_pos_nonzero("not a number"), 79 | Err(ParsePosNonzeroError::ParseInt(_)) 80 | )); 81 | } 82 | 83 | #[test] 84 | fn test_negative() { 85 | assert_eq!( 86 | parse_pos_nonzero("-555"), 87 | Err(ParsePosNonzeroError::Creation(CreationError::Negative)) 88 | ); 89 | } 90 | 91 | #[test] 92 | fn test_zero() { 93 | assert_eq!( 94 | parse_pos_nonzero("0"), 95 | Err(ParsePosNonzeroError::Creation(CreationError::Zero)) 96 | ); 97 | } 98 | 99 | #[test] 100 | fn test_positive() { 101 | let x = PositiveNonzeroInteger::new(42); 102 | assert!(x.is_ok()); 103 | assert_eq!(parse_pos_nonzero("42"), Ok(x.unwrap())); 104 | } 105 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/functions/README.md: -------------------------------------------------------------------------------- 1 | # Functions 2 | 3 | * [How Functions Work](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/functions/functions1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | call_me(); 3 | } 4 | 5 | fn call_me() { 6 | println!("{}", "Call Me"); 7 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/functions/functions2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | call_me(3); 3 | } 4 | 5 | fn call_me(num: i32) { 6 | for i in 0..num { 7 | println!("Ring! Call number {}", i + 1); 8 | } 9 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/functions/functions3.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | call_me(5); 3 | } 4 | 5 | fn call_me(num: u32) { 6 | for i in 0..num { 7 | println!("Ring! Call number {}", i + 1); 8 | } 9 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/functions/functions4.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let original_price = 51; 3 | println!("Your sale price is {}", sale_price(original_price)); 4 | } 5 | 6 | fn sale_price(price: i32) -> i32 { 7 | if is_even(price) { 8 | price - 10 9 | } else { 10 | price - 3 11 | } 12 | } 13 | 14 | fn is_even(num: i32) -> bool { 15 | num %2 == 0 16 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/functions/functions5.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let answer = square(3); 3 | println!("The answer is {}", answer); 4 | } 5 | 6 | fn square(num: i32) -> i32 { 7 | num * num 8 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/generics/README.md: -------------------------------------------------------------------------------- 1 | # Generics(泛型) 2 | 3 | 泛型对减少重复代码非常有用,但可能带来相当复杂的语法。泛型最简单和最常见的用途是用于类型参数。 4 | 5 |   6 | 7 | ## Further information 8 | 9 | * [Generic Data Types](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html) 10 | * [Bounds](https://doc.rust-lang.org/rust-by-example/generics/bounds.html) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/generics/generics1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut shopping_list: Vec<&str> = Vec::new(); 3 | shopping_list.push("milk"); 4 | 5 | println!("{:?}", shopping_list); 6 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/generics/generics2.rs: -------------------------------------------------------------------------------- 1 | struct Wrapper { 2 | value: T, 3 | } 4 | 5 | impl Wrapper { 6 | pub fn new(value: T) -> Self { 7 | Wrapper {value} 8 | } 9 | } 10 | 11 | #[cfg(test)] 12 | mod tests { 13 | use super::*; 14 | 15 | #[test] 16 | fn store_u32_in_wrapper() { 17 | assert_eq!(Wrapper::new(42).value, 42); 18 | } 19 | 20 | #[test] 21 | fn store_str_in_wrapper() { 22 | assert_eq!(Wrapper::new("Foo").value, "Foo"); 23 | } 24 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/generics/generics3.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | pub struct ReportCard { 4 | pub grade: T, 5 | pub student_name: String, 6 | pub student_age: u8, 7 | } 8 | 9 | impl ReportCard { 10 | // T 泛型默认不支持`format!()` 进行格式化,可通过 `Display` 以支持. 11 | pub fn print(&self) -> String where T: Display { 12 | format!("{} ({}) - achieved a grade of {}", 13 | &self.student_name, &self.student_age, &self.grade) 14 | } 15 | } 16 | 17 | 18 | #[cfg(test)] 19 | mod tests { 20 | use super::*; 21 | 22 | #[test] 23 | fn generate_numeric_report_card() { 24 | let report_card = ReportCard { 25 | grade: 2.1, 26 | student_name: "Tom Wriggle".to_string(), 27 | student_age: 12, 28 | }; 29 | 30 | assert_eq!(report_card.print(), 31 | "Tom Wriggle (12) - achieved a grade of 2.1"); 32 | } 33 | 34 | #[test] 35 | fn generate_alphabetic_report_card() { 36 | let report_card = ReportCard { 37 | grade: "A+", 38 | student_name: "Gary Plotter".to_string(), 39 | student_age: 11, 40 | }; 41 | 42 | assert_eq!( 43 | report_card.print(), 44 | "Gary Plotter (11) - achieved a grade of A+" 45 | ); 46 | } 47 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/if/RADEME.md: -------------------------------------------------------------------------------- 1 | # if 2 | 3 | `if`,用于数据流控制。 4 | 5 | ## Further information 6 | 7 | * [Control Flow - if expressions](https://doc.rust-lang.org/book/ch03-05-control-flow.html#if-expressions) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/if/if1.rs: -------------------------------------------------------------------------------- 1 | pub fn bigger(a: i32, b: i32) -> i32 { 2 | if a > b { 3 | return a; 4 | } 5 | b 6 | } 7 | 8 | #[cfg(test)] 9 | mod tests { 10 | use super::*; 11 | 12 | #[test] 13 | fn ten_is_bigger_than_eight() { 14 | assert_eq!(10, bigger(10, 8)); 15 | } 16 | 17 | #[test] 18 | fn fortytwo_is_bigger_than_ghirtytwo() { 19 | assert_eq!(42, bigger(32, 42)); 20 | } 21 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/if/if2.rs: -------------------------------------------------------------------------------- 1 | pub fn fizz_if_foo(fizzish: &str) -> &str { 2 | if fizzish == "fizz" { 3 | "foo" 4 | } else if fizzish == "fuzz" { 5 | "bar" 6 | } else { 7 | "baz" 8 | } 9 | } 10 | 11 | #[cfg(test)] 12 | mod tests { 13 | use super::*; 14 | 15 | #[test] 16 | fn foo_for_fizz() { 17 | assert_eq!(fizz_if_foo("fizz"), "foo"); 18 | } 19 | 20 | #[test] 21 | fn bar_foo_fuzz() { 22 | assert_eq!(fizz_if_foo("fuzz"), "bar") 23 | } 24 | 25 | #[test] 26 | fn default_to_baz() { 27 | assert_eq!(fizz_if_foo("literally anything"), "baz") 28 | } 29 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/macros/README.md: -------------------------------------------------------------------------------- 1 | # Macros 2 | 3 | Rust的宏系统非常强大,但也有点儿难以理解。通过几个练习,展示如何使用和创建它们。 4 | 5 | ## Further information 6 | 7 | * [Macros](https://doc.rust-lang.org/book/ch19-06-macros.html) 8 | * [The Little Book of Rust Macros](https://danielkeep.github.io/tlborm/book/index.html) 9 | -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/macros/macros1.rs: -------------------------------------------------------------------------------- 1 | macro_rules! my_macro { 2 | () => { 3 | println!("Check out my macro!"); 4 | }; 5 | } 6 | 7 | fn main() { 8 | my_macro!(); 9 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/macros/macros2.rs: -------------------------------------------------------------------------------- 1 | mod macros { 2 | macro_rules! my_macro { 3 | () => { 4 | println!("Check out my macro!"); 5 | }; 6 | } 7 | 8 | pub(crate) use my_macro; // New method(since Rust 1.32,2019-01-17) 9 | } 10 | 11 | fn main() { 12 | macros::my_macro!(); 13 | } 14 | 15 | /* 16 | * // Old method 17 | * 18 | * #[macro_use] 19 | * mod macros { 20 | * macro_rules! my_macro { 21 | * () => { 22 | * println!("Check out my macro"); 23 | * }; 24 | * } 25 | * } 26 | * 27 | * fn main() { 28 | * my_macro!(); 29 | * } 30 | * 31 | */ 32 | -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/macros/macros3.rs: -------------------------------------------------------------------------------- 1 | macro_rules! my_macro { 2 | () => { 3 | println!("Check out my macro!"); 4 | }; 5 | 6 | ($val:expr) => { 7 | println!("Look at this other macro: {}", $val); 8 | }; 9 | } 10 | 11 | fn main() { 12 | my_macro!(); 13 | 14 | my_macro!(7777); 15 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/modules/README.md: -------------------------------------------------------------------------------- 1 | # Modules 2 | 3 | Rust 模块系统. 4 | 5 | ## Further information 6 | 7 | * [The Module System](https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/modules/modules1.rs: -------------------------------------------------------------------------------- 1 | pub mod sausage_factory { 2 | fn get_secret_recipe() -> String { 3 | String::from("Ginger") 4 | } 5 | 6 | pub fn make_sausage() { 7 | get_secret_recipe(); 8 | println!("sausage!"); 9 | } 10 | 11 | } 12 | 13 | fn main() { 14 | sausage_factory::make_sausage(); 15 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/modules/modules2.rs: -------------------------------------------------------------------------------- 1 | pub mod delicious_snacks { 2 | pub use self::fruits::PEAR as fruit; 3 | pub use self::veggies::CUCUMBER as veggie; 4 | 5 | pub mod fruits { 6 | pub const PEAR: &'static str = "Pear"; 7 | pub const APPLE: &'static str = "Apple"; 8 | } 9 | 10 | pub mod veggies { 11 | pub const CUCUMBER: &'static str = "Cucumber"; 12 | pub const CARROT: &'static str = "Carrot"; 13 | } 14 | } 15 | 16 | fn main() { 17 | println!( 18 | "favorite snacks: {} and {}", 19 | delicious_snacks::fruit, 20 | delicious_snacks::veggie 21 | ); 22 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/modules/modules3.rs: -------------------------------------------------------------------------------- 1 | use std::time::{SystemTime, UNIX_EPOCH}; 2 | 3 | fn main() { 4 | match SystemTime::now().duration_since(UNIX_EPOCH) { 5 | Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()), 6 | Err(_) => panic!("SystemTime before UNIX EPOCH!"), 7 | } 8 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/move_semantics/README.md: -------------------------------------------------------------------------------- 1 | # Move Semantics 2 | 3 | ## Further information 4 | 5 | * [Ownership](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html) 6 | * [Reference and borrowing](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/move_semantics/move_semantics1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let vec0 = Vec::new(); 3 | 4 | let mut vec1 = fill_vec(vec0); // vec0 Move!!! 所有权转移 5 | 6 | println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); 7 | 8 | vec1.push(88); 9 | 10 | println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); 11 | } 12 | 13 | fn fill_vec(vec: Vec) -> Vec { 14 | let mut vec = vec; 15 | 16 | vec.push(22); 17 | vec.push(44); 18 | vec.push(66); 19 | 20 | vec 21 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/move_semantics/move_semantics2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut vec0 = Vec::new(); 3 | 4 | let mut vec1 = fill_vec(&mut vec0); // mut vec0 borrow!!! 借用!!! 5 | 6 | // Do not change the following line! 7 | println!("{} has length {} content `{:?}`", "vec0", vec0.len(), vec0); // vec0 可以继续使用!!! 8 | 9 | vec1.push(88); 10 | 11 | println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); 12 | } 13 | 14 | fn fill_vec<'a>(vec: &'a mut Vec) -> Vec { 15 | vec.push(22); 16 | vec.push(44); 17 | vec.push(66); 18 | 19 | let vec1 = vec.clone(); 20 | vec1 21 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/move_semantics/move_semantics3.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut vec0 = Vec::new(); 3 | 4 | let mut vec1 = fill_vec(&mut vec0); 5 | 6 | println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); 7 | 8 | vec1.push(88); 9 | 10 | println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); 11 | } 12 | 13 | 14 | fn fill_vec(vec: &mut Vec) -> Vec { 15 | vec.push(22); 16 | vec.push(44); 17 | vec.push(66); 18 | 19 | vec.clone() 20 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/move_semantics/move_semantics4.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut x = 100; 3 | let y = &mut x; 4 | *y += 100; 5 | 6 | let z = &mut x; 7 | *z += 1000; 8 | assert_eq!(x, 1200); 9 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/options/README.md: -------------------------------------------------------------------------------- 1 | # Option 2 | 3 | `Option` 是一个可选值,每个 `Option` 要么是 `Some` 并且包含一个值,要么 `None` 并且不包含。`Option`在Rust中很常见,因为它们有以下用途: 4 | 5 | * 初始值 6 | * 函数返回值 7 | * 函数返回值包含错误信息的处理(错误时返回`None`) 8 | * 可选的结构体字段 9 | * 空指针 10 | * ... 11 | 12 | ## Further Information 13 | 14 | * [Option Enum Format](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-enum-definitions) 15 | * [Option Module Documentation](https://doc.rust-lang.org/std/option/) 16 | * [Option Enum Documentation](https://doc.rust-lang.org/std/option/enum.Option.html) 17 | -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/options/option1.rs: -------------------------------------------------------------------------------- 1 | fn print_number(maybe_number: Option) { 2 | println!("printing: {}", maybe_number.unwrap()); 3 | } 4 | 5 | fn main() { 6 | print_number(Some(13)); 7 | print_number(Some(15)); 8 | 9 | // Slice(切片)是一种没有所有权的数据类型。切片引用连续的内存分配而不是整个集合。 10 | // Slice(切片)不能直接创建,而是从现有变量创建的。切片由长度组成,并且可以是可变的或不可变的。 11 | // Slice(切片)的行为与数组相同。 12 | let mut numbers: [Option; 5] = [Some(0); 5]; 13 | for iter in 0..5 { 14 | let number_to_add: u16 = { 15 | ((iter * 1235) + 2) / (4*16) 16 | }; 17 | 18 | numbers[iter as usize] = Some(number_to_add); 19 | } 20 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/options/option2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let optional_word = Some(String::from("rustlings")); 3 | 4 | if let word = optional_word { 5 | println!("The word is: {:?}", word); 6 | } else { 7 | println!("The optional word doesn't contain anything"); 8 | } 9 | 10 | let mut optional_integers_vec: Vec> = Vec::new(); 11 | for x in 1..10 { 12 | optional_integers_vec.push(Some(x)); 13 | } 14 | 15 | if let integer = optional_integers_vec.pop() { 16 | println!("current value: {:?}", integer); 17 | } 18 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/options/option3.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct Point { 3 | x: i32, 4 | y: i32, 5 | } 6 | 7 | fn main() { 8 | let y: Option = Some(Point{ x: 100, y: 200 }); 9 | 10 | match &y { 11 | Some(p) => println!("Co-ordinates are {}, {}", p.x, p.y), 12 | _ => println!("no match"), 13 | } 14 | 15 | println!("{:?}", y); 16 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/primitive_types/README.md: -------------------------------------------------------------------------------- 1 | # Primitive Types 2 | 3 | Rust中有几个基本类型可以直接在编译器中实现。 4 | 5 | ## Further information 6 | 7 | * [Data Types](https://doc.rust-lang.org/stable/book/ch03-02-data-types.html) 8 | * [The Slice Type](https://doc.rust-lang.org/stable/book/ch04-03-slices.html) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/primitive_types/primitive_type4.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn slice_out_of_array() { 3 | let a = [1, 2, 3, 4, 5]; 4 | let nice_slice = &a[1..=3]; 5 | 6 | assert_eq!([2, 3, 4], nice_slice); 7 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/primitive_types/primitive_type5.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let cat = ("Furry McFurson", 3.5); 3 | let (name, age) = cat; 4 | 5 | println!("{} is {} years old.", name, age); 6 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/primitive_types/primitive_type6.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn indexing_tuple() { 3 | let numbers = (1, 2, 3); 4 | let second = numbers.1; 5 | 6 | assert_eq!(2, second, "This is not the 2nd number in the tuple!"); 7 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/primitive_types/primitive_types1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // Booleans 3 | 4 | let is_morning = true; 5 | if is_morning { 6 | println!("Good morning!"); 7 | } 8 | 9 | let is_evening = true; 10 | if is_evening { 11 | println!("Good evening!"); 12 | } 13 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/primitive_types/primitive_types2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let my_first_initial = 'C'; 3 | if my_first_initial.is_alphabetic() { 4 | println!("Alphabetical!"); 5 | } else if my_first_initial.is_numeric() { 6 | println!("Numerical!"); 7 | } else { 8 | println!("Neither alphabetic nor numeric!"); 9 | } 10 | 11 | 12 | let your_character = '🔥'; 13 | if your_character.is_alphabetic() { 14 | println!("Alphabetical!"); 15 | } else if your_character.is_numeric() { 16 | println!("Numerical!"); 17 | } else { 18 | println!("Neither alphabetic nor numeric!"); 19 | } 20 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/primitive_types/primitive_types3.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let a = [1, 2, 3, 4, 5, 6, 7, 8, 9]; 3 | 4 | if a.len() >= 100 { 5 | println!("Wow, that's a big array!"); 6 | } else { 7 | println!("Meh, I eat arrays like that for breakfast."); 8 | } 9 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/quiz1.rs: -------------------------------------------------------------------------------- 1 | fn calculate_apple_price(num: i32) ->i32 { 2 | if num <= 40 { 3 | return num * 2; 4 | } 5 | num 6 | } 7 | 8 | #[test] 9 | fn verify_test() { 10 | let price1 = calculate_apple_price(35); 11 | let price2 = calculate_apple_price(40); 12 | let price3 = calculate_apple_price(65); 13 | 14 | assert_eq!(70, price1); 15 | assert_eq!(80, price2); 16 | assert_eq!(65, price3); 17 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/quiz2.rs: -------------------------------------------------------------------------------- 1 | fn string_slice(arg: &str) { 2 | println!("{}", arg); 3 | } 4 | 5 | fn string(arg: String) { 6 | println!("{}", arg); 7 | } 8 | 9 | fn main() { 10 | string_slice("blue"); 11 | string("red".to_string()); 12 | string(String::from("hi")); 13 | string("rust is fun!".to_owned()); 14 | string_slice("nice weather".into()); 15 | string(format!("Interpolation {}", "Station")); 16 | string_slice(&String::from("abc")[0..1]); 17 | string_slice(" hello there ".trim()); 18 | string("Happy Monday!".to_string().replace("Mon", "Tues")); 19 | string("mY sHiFt KeY iS sTiCkY.".to_lowercase()); 20 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/quiz3.rs: -------------------------------------------------------------------------------- 1 | pub fn times_two(num: i32) -> i32 { 2 | num * 2 3 | } 4 | 5 | #[cfg(test)] 6 | mod tests { 7 | use super::*; 8 | 9 | #[test] 10 | fn returns_twice_of_positive_numbers() { 11 | assert_eq!(times_two(4), 8); 12 | } 13 | 14 | #[test] 15 | fn returns_twice_of_negative_numbers() { 16 | assert_eq!(times_two(-4), -8); 17 | } 18 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/quiz4.rs: -------------------------------------------------------------------------------- 1 | macro_rules! my_macro { 2 | ($val:expr) => { 3 | format!("Hello {}", $val) 4 | }; 5 | } 6 | 7 | #[cfg(test)] 8 | mod tests { 9 | #[test] 10 | fn test_my_macro_world() { 11 | assert_eq!(my_macro!("world!"), "Hello world!"); 12 | } 13 | 14 | #[test] 15 | fn test_my_macro_goodbye() { 16 | assert_eq!(my_macro!("goodbye!"), "Hello goodbye!"); 17 | } 18 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/standard_library_types/README.md: -------------------------------------------------------------------------------- 1 | # Standard library types 2 | 3 | 本章包括 `Box`、`共享状态并发`和`迭代器`内容。 4 | 5 | ## Further information 6 | 7 | * [Using Box to Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html) 8 | * [Shared-State Concurrency](https://doc.rust-lang.org/book/ch16-03-shared-state.html) 9 | * [Iterator](https://doc.rust-lang.org/book/ch13-02-iterators.html) 10 | * [Iterator documentation](https://doc.rust-lang.org/stable/std/iter/) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/standard_library_types/arc1.rs: -------------------------------------------------------------------------------- 1 | #![forbid(unused_imports)] 2 | use std::sync::Arc; 3 | use std::thread; 4 | 5 | fn main() { 6 | let numbers: Vec<_> = (0..100u32).collect(); 7 | let shared_numbers = Arc::new(numbers); 8 | let mut joinhandles = Vec::new(); 9 | 10 | for offset in 0..8 { 11 | let child_numbers = Arc::clone(&shared_numbers); 12 | joinhandles.push(thread::spawn(move || { 13 | let mut i = offset; 14 | let mut sum = 0; 15 | while i < child_numbers.len() { 16 | sum += child_numbers[i]; 17 | i += 8; 18 | } 19 | println!("Sum of offset {} is {}", offset, sum); 20 | })); 21 | } 22 | 23 | for handle in joinhandles.into_iter() { 24 | handle.join().unwrap(); 25 | } 26 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/standard_library_types/box1.rs: -------------------------------------------------------------------------------- 1 | #[derive(PartialEq, Debug)] 2 | pub enum List { 3 | Cons(i32, Box), 4 | Nil, 5 | } 6 | 7 | fn main() { 8 | println!("This is an empty cons list: {:?}", create_empty_list()); 9 | println!("This is a non-empty cons list: {:?}", create_non_empty_list()); 10 | } 11 | 12 | pub fn create_empty_list() -> List { 13 | List::Nil 14 | } 15 | 16 | pub fn create_non_empty_list() -> List { 17 | List::Cons(0, Box::from(List::Nil)) 18 | } 19 | 20 | #[cfg(test)] 21 | mod tests { 22 | use super::*; 23 | 24 | #[test] 25 | fn test_create_empty_list() { 26 | assert_eq!(List::Nil, create_empty_list()); 27 | } 28 | 29 | #[test] 30 | fn test_create_non_empty_list() { 31 | assert_ne!(create_empty_list(), create_non_empty_list()); 32 | } 33 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/standard_library_types/iterators1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let my_fav_fruits = vec!["banana", "custard apple", "avocado", "peach", "raspberry"]; 3 | 4 | let mut my_iterable_fav_fruits = my_fav_fruits.iter(); 5 | 6 | assert_eq!(my_iterable_fav_fruits.next(), Some(&"banana")); 7 | assert_eq!(my_iterable_fav_fruits.next(), Some(&"custard apple")); 8 | assert_eq!(my_iterable_fav_fruits.next(), Some(&"avocado")); 9 | assert_eq!(my_iterable_fav_fruits.next(), Some(&"peach")); 10 | assert_eq!(my_iterable_fav_fruits.next(), Some(&"raspberry")); 11 | assert_eq!(my_iterable_fav_fruits.next(), None); 12 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/standard_library_types/iterators2.rs: -------------------------------------------------------------------------------- 1 | // "hello" -> "Hello" 2 | pub fn capitalize_first(input: &str) -> String { 3 | let mut c = input.chars(); 4 | match c.next() { 5 | None => String::new(), 6 | // Some(first) => first.to_uppercase().chain(c).collect(), 7 | Some(first) => format!("{}{}", first.to_uppercase(), c.as_str()), 8 | } 9 | } 10 | 11 | // ["hello", "world"] -> ["Hello", "World"] 12 | pub fn capitalize_words_vector(words: &[&str]) -> Vec { 13 | words.iter().map(|w| capitalize_first(&w)).collect() 14 | } 15 | 16 | 17 | // ["hello", " ", "world"] -> "Hello World" 18 | pub fn capitalize_words_string(words: &[&str]) -> String { 19 | words.iter().map(|w| capitalize_first(&w)).fold(String::new(), |sum, val| format!("{}{}", sum, val)) 20 | } 21 | 22 | #[cfg(test)] 23 | mod tests { 24 | use super::*; 25 | 26 | #[test] 27 | fn test_success() { 28 | assert_eq!(capitalize_first("hello"), "Hello"); 29 | } 30 | 31 | #[test] 32 | fn test_empty() { 33 | assert_eq!(capitalize_first(""), ""); 34 | } 35 | 36 | #[test] 37 | fn test_iterate_string_vec() { 38 | let words = vec!["hello", "world"]; 39 | assert_eq!(capitalize_words_vector(&words), ["Hello", "World"]); 40 | } 41 | 42 | #[test] 43 | fn test_iterate_into_string() { 44 | let words = vec!["hello", " ", "world"]; 45 | assert_eq!(capitalize_words_string(&words), "Hello World"); 46 | } 47 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/standard_library_types/iterators3.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, PartialEq, Eq)] 2 | pub enum DivisionError { 3 | NotDivisible(NotDivisibleError), 4 | DivideByZero, 5 | } 6 | 7 | #[derive(Debug, PartialEq, Eq)] 8 | pub struct NotDivisibleError { 9 | dividend: i32, 10 | divisor: i32, 11 | } 12 | 13 | pub fn divide(a: i32, b: i32) -> Result { 14 | if b == 0 { 15 | Err(DivisionError::DivideByZero) 16 | } else if a % b == 0 { 17 | Ok(a/b) 18 | } else { 19 | Err(DivisionError::NotDivisible(NotDivisibleError{dividend: a,divisor: b})) 20 | } 21 | } 22 | 23 | fn result_with_list() -> Result, DivisionError> { 24 | let numbers = vec![27, 297, 38502, 81]; 25 | let division_results = numbers.into_iter().map(|n| divide(n, 27)); 26 | let x: Result, DivisionError> = Ok(division_results.collect::>().into_iter().map(|x| x.unwrap_or(-1)).collect::>()); 27 | x 28 | } 29 | 30 | fn list_of_results() -> Vec> { 31 | let numbers = vec![27, 297, 38502, 81]; 32 | let division_results = numbers.into_iter().map(|n| divide(n, 27)).collect::>>(); 33 | division_results 34 | } 35 | 36 | #[cfg(test)] 37 | mod tests { 38 | use super::*; 39 | 40 | #[test] 41 | fn test_success() { 42 | assert_eq!(divide(81, 9), Ok(9)); 43 | } 44 | 45 | #[test] 46 | fn test_not_divisible() { 47 | assert_eq!( 48 | divide(81, 6), 49 | Err(DivisionError::NotDivisible(NotDivisibleError { 50 | dividend: 81, 51 | divisor: 6 52 | })) 53 | ); 54 | } 55 | 56 | #[test] 57 | fn test_divide_by_0() { 58 | assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero)); 59 | } 60 | 61 | #[test] 62 | fn test_divide_0_by_something() { 63 | assert_eq!(divide(0, 81), Ok(0)); 64 | } 65 | 66 | #[test] 67 | fn test_result_with_list() { 68 | assert_eq!(format!("{:?}", result_with_list()), "Ok([1, 11, 1426, 3])"); 69 | } 70 | 71 | #[test] 72 | fn test_list_of_results() { 73 | assert_eq!( 74 | format!("{:?}", list_of_results()), 75 | "[Ok(1), Ok(11), Ok(1426), Ok(3)]" 76 | ); 77 | } 78 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/standard_library_types/iterators4_fold.rs: -------------------------------------------------------------------------------- 1 | pub fn factorial(num: u64) -> u64 { 2 | // fold(): 通过操作符将每次执行结果值进行叠加 3 | (1..num + 1).fold(1, |acc, x| acc * x) 4 | } 5 | 6 | fn main() { 7 | println!("{}", factorial(20)); 8 | } 9 | 10 | #[cfg(test)] 11 | mod tests { 12 | use super::*; 13 | 14 | #[test] 15 | fn factorial_of_1() { 16 | assert_eq!(1, factorial(1)); 17 | } 18 | 19 | #[test] 20 | fn factorial_of_2() { 21 | assert_eq!(2, factorial(2)); 22 | } 23 | 24 | #[test] 25 | fn factorial_of_4() { 26 | assert_eq!(24, factorial(4)); 27 | } 28 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/standard_library_types/iterators4_if.rs: -------------------------------------------------------------------------------- 1 | pub fn factorial(num: u64) -> u64 { 2 | if num <= 0 { 3 | 1 4 | } else { 5 | num * factorial(num - 1) 6 | } 7 | } 8 | 9 | fn main() { 10 | println!("{}", factorial(20)); 11 | } 12 | 13 | #[cfg(test)] 14 | mod tests { 15 | use super::*; 16 | 17 | #[test] 18 | fn factorial_of_1() { 19 | assert_eq!(1, factorial(1)); 20 | } 21 | 22 | #[test] 23 | fn factorial_of_2() { 24 | assert_eq!(2, factorial(2)); 25 | } 26 | 27 | #[test] 28 | fn factorial_of_4() { 29 | assert_eq!(24, factorial(4)); 30 | } 31 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/standard_library_types/iterators4_imp.rs: -------------------------------------------------------------------------------- 1 | pub fn factorial(num: u64) -> u64 { 2 | let mut r = 1; 3 | for i in 1..num+1 { 4 | r = r * i; 5 | } 6 | r 7 | } 8 | 9 | fn main() { 10 | println!("{}", factorial(20)); 11 | } 12 | 13 | #[cfg(test)] 14 | mod tests { 15 | use super::*; 16 | 17 | #[test] 18 | fn factorial_of_1() { 19 | assert_eq!(1, factorial(1)); 20 | } 21 | 22 | #[test] 23 | fn factorial_of_2() { 24 | assert_eq!(2, factorial(2)); 25 | } 26 | 27 | #[test] 28 | fn factorial_of_4() { 29 | assert_eq!(24, factorial(4)); 30 | } 31 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/standard_library_types/iterators4_match.rs: -------------------------------------------------------------------------------- 1 | pub fn factorial(num: u64) -> u64 { 2 | match num { 3 | 1 => 1, 4 | _ => num * factorial(num - 1) 5 | } 6 | } 7 | 8 | fn main() { 9 | println!("{}", factorial(20)); 10 | } 11 | 12 | #[cfg(test)] 13 | mod tests { 14 | use super::*; 15 | 16 | #[test] 17 | fn factorial_of_1() { 18 | assert_eq!(1, factorial(1)); 19 | } 20 | 21 | #[test] 22 | fn factorial_of_2() { 23 | assert_eq!(2, factorial(2)); 24 | } 25 | 26 | #[test] 27 | fn factorial_of_4() { 28 | assert_eq!(24, factorial(4)); 29 | } 30 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/standard_library_types/iterators4_product.rs: -------------------------------------------------------------------------------- 1 | pub fn factorial(num: u64) -> u64 { 2 | (1..=num).product() 3 | } 4 | 5 | fn main() { 6 | println!("{}", factorial(20)); 7 | } 8 | 9 | #[cfg(test)] 10 | mod tests { 11 | use super::*; 12 | 13 | #[test] 14 | fn factorial_of_1() { 15 | assert_eq!(1, factorial(1)); 16 | } 17 | 18 | #[test] 19 | fn factorial_of_2() { 20 | assert_eq!(2, factorial(2)); 21 | } 22 | 23 | #[test] 24 | fn factorial_of_4() { 25 | assert_eq!(24, factorial(4)); 26 | } 27 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/standard_library_types/iterators5.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | #[derive(Clone, Copy, PartialEq, Eq)] 4 | enum Progress { 5 | None, 6 | Some, 7 | Complete, 8 | } 9 | 10 | fn count_for(map: &HashMap, value: Progress) -> usize { 11 | let mut count = 0; 12 | for val in map.values() { 13 | if val == &value { 14 | count += 1; 15 | } 16 | } 17 | count 18 | } 19 | 20 | fn count_iterator(map: &HashMap, value: Progress) -> usize { 21 | map.values().into_iter().filter(|&v| *v == value).count() 22 | } 23 | 24 | fn count_collection_for(collection: &[HashMap], value: Progress) -> usize { 25 | let mut count = 0; 26 | for map in collection { 27 | for val in map.values() { 28 | if val == &value { 29 | count += 1; 30 | } 31 | } 32 | } 33 | count 34 | } 35 | 36 | fn count_collection_iterator(collection: &[HashMap], value: Progress) -> usize { 37 | collection.iter().map(|m| count_iterator(m, value)).fold(0, |acc, n| acc + n) 38 | } 39 | 40 | #[cfg(test)] 41 | mod tests { 42 | use super::*; 43 | 44 | #[test] 45 | fn count_complete() { 46 | let map = get_map(); 47 | assert_eq!(3, count_iterator(&map, Progress::Complete)); 48 | } 49 | 50 | #[test] 51 | fn count_equals_for() { 52 | let map = get_map(); 53 | assert_eq!( 54 | count_for(&map, Progress::Complete), 55 | count_iterator(&map, Progress::Complete) 56 | ); 57 | } 58 | 59 | #[test] 60 | fn count_collection_complete() { 61 | let collection = get_vec_map(); 62 | assert_eq!( 63 | 6, 64 | count_collection_iterator(&collection, Progress::Complete) 65 | ); 66 | } 67 | 68 | #[test] 69 | fn count_collection_equals_for() { 70 | let collection = get_vec_map(); 71 | assert_eq!( 72 | count_collection_for(&collection, Progress::Complete), 73 | count_collection_iterator(&collection, Progress::Complete) 74 | ); 75 | } 76 | 77 | fn get_map() -> HashMap { 78 | use Progress::*; 79 | 80 | let mut map = HashMap::new(); 81 | map.insert(String::from("variables1"), Complete); 82 | map.insert(String::from("functions1"), Complete); 83 | map.insert(String::from("hashmap1"), Complete); 84 | map.insert(String::from("arc1"), Some); 85 | map.insert(String::from("as_ref_mut"), None); 86 | map.insert(String::from("from_str"), None); 87 | 88 | map 89 | } 90 | 91 | fn get_vec_map() -> Vec> { 92 | use Progress::*; 93 | 94 | let map = get_map(); 95 | 96 | let mut other = HashMap::new(); 97 | other.insert(String::from("variables2"), Complete); 98 | other.insert(String::from("functions2"), Complete); 99 | other.insert(String::from("if1"), Complete); 100 | other.insert(String::from("from_into"), None); 101 | other.insert(String::from("try_from_into"), None); 102 | 103 | vec![map, other] 104 | } 105 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/strings/README.md: -------------------------------------------------------------------------------- 1 | # String 2 | 3 | Rust有两种字符串类型,一个字符串切片(`&str`)和一个拥有的字符串(`String`)。根据需要合理选择字符串使用。 4 | 5 | ## Further information 6 | 7 | [Strings](https://doc.rust-lang.org/book/ch08-02-strings.html) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/strings/strings1.rs: -------------------------------------------------------------------------------- 1 | fn current_favorite_color() -> String { 2 | let s = String::from("blue"); 3 | s 4 | } 5 | 6 | fn main() { 7 | // answer: string type 8 | let answer = current_favorite_color(); 9 | println!("My current favorite color is {}", answer); 10 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/strings/strings2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let word = String::from("green"); 3 | 4 | // 参数是&str类型 5 | if is_a_color_word(&word) { 6 | println!("That is a color word I know."); 7 | } else { 8 | println!("That is not a color word I know."); 9 | } 10 | } 11 | 12 | fn is_a_color_word(attempt: &str) -> bool { 13 | attempt == "green" || attempt == "blue" || attempt == "red" 14 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/structs/README.md: -------------------------------------------------------------------------------- 1 | # Structs 2 | 3 | Rust 有三种数据类型:`classic struct`、`tuple struct` 和 `unit struct`。 4 | 5 |   6 | 7 | ## Further information 8 | 9 | * [Structures](https://doc.rust-lang.org/book/ch05-01-defining-structs.html) 10 | * [Method Syntax](https://doc.rust-lang.org/book/ch05-03-method-syntax.html) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/structs/structs1.rs: -------------------------------------------------------------------------------- 1 | struct ColorClassicStruct<'a> { 2 | name: &'a str, 3 | hex: &'a str, 4 | } 5 | 6 | struct ColorTupleStruct( 7 | String, 8 | String, 9 | ); 10 | 11 | #[derive(Debug)] 12 | struct UnitStruct; 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use super::*; 17 | 18 | #[test] 19 | fn classic_structs() { 20 | let green = ColorClassicStruct{ 21 | name: "green", 22 | hex: "#00FF00", 23 | }; 24 | 25 | assert_eq!(green.name, "green"); 26 | assert_eq!(green.hex, "#00FF00"); 27 | } 28 | 29 | #[test] 30 | fn tuple_structs() { 31 | let green = ColorTupleStruct( 32 | "green".to_string(), 33 | "#00FF00".to_string(), 34 | ); 35 | 36 | assert_eq!(&green.0, "green"); 37 | assert_eq!(&green.1, "#00FF00"); 38 | } 39 | 40 | #[test] 41 | fn unit_struct() { 42 | let unit_struct = UnitStruct; 43 | let message = format!("{:?}s are fun!", unit_struct); 44 | assert_eq!(message, "UnitStructs are fun!"); 45 | } 46 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/structs/structs2.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct Order { 3 | name: String, 4 | year: u32, 5 | made_by_phone: bool, 6 | made_by_mobile: bool, 7 | made_by_email: bool, 8 | item_number: u32, 9 | count: u32, 10 | } 11 | 12 | fn create_order_template() -> Order { 13 | Order { 14 | name: String::from("Bob"), 15 | year: 2019, 16 | made_by_phone: false, 17 | made_by_mobile: false, 18 | made_by_email: true, 19 | item_number: 123, 20 | count: 0, 21 | } 22 | } 23 | 24 | #[cfg(test)] 25 | mod tests { 26 | use super::*; 27 | 28 | #[test] 29 | fn your_order() { 30 | let order_template = create_order_template(); 31 | let your_order = Order { 32 | name: String::from("Hacker in Rust"), 33 | year: 2019, 34 | made_by_phone: false, 35 | made_by_mobile: false, 36 | made_by_email: true, 37 | item_number: 123, 38 | count: 1, 39 | }; 40 | 41 | assert_eq!(your_order.name, "Hacker in Rust"); 42 | assert_eq!(your_order.year, order_template.year); 43 | assert_eq!(your_order.made_by_phone, order_template.made_by_phone); 44 | assert_eq!(your_order.made_by_mobile, order_template.made_by_mobile); 45 | assert_eq!(your_order.made_by_email, order_template.made_by_email); 46 | assert_eq!(your_order.item_number, order_template.item_number); 47 | assert_eq!(your_order.count, 1); 48 | } 49 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/structs/structs3.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct Package { 3 | sender_country: String, 4 | recipient_country: String, 5 | weight_in_grams: i32, 6 | } 7 | 8 | impl Package { 9 | fn new(sender_country: String, recipient_country: String, weight_in_grams: i32) -> Package { 10 | if weight_in_grams <= 0 { 11 | panic!() 12 | } else { 13 | return Package { 14 | sender_country, 15 | recipient_country, 16 | weight_in_grams, 17 | }; 18 | } 19 | } 20 | 21 | fn is_international(&self) -> bool { 22 | if self.sender_country == self.recipient_country { 23 | return false 24 | } 25 | return true 26 | } 27 | 28 | fn get_fees(&self, cents_per_gram: i32) -> i32 { 29 | self.weight_in_grams + cents_per_gram 30 | } 31 | } 32 | 33 | #[cfg(test)] 34 | mod tests { 35 | use super::*; 36 | 37 | #[test] 38 | #[should_panic] 39 | fn fail_creating_weightless_package() { 40 | let sender_country = String::from("Spain"); 41 | let recipient_country = String::from("Austria"); 42 | 43 | Package::new(sender_country, recipient_country, -2210); 44 | } 45 | 46 | #[test] 47 | fn create_international_package() { 48 | let sender_country = String::from("Spain"); 49 | let recipient_country = String::from("Russia"); 50 | 51 | let package = Package::new(sender_country, recipient_country, 1200); 52 | assert!(package.is_international()); 53 | } 54 | 55 | #[test] 56 | fn create_local_package() { 57 | let sender_country = String::from("Canada"); 58 | let recipient_country = sender_country.clone(); 59 | 60 | let package = Package::new(sender_country, recipient_country, 1200); 61 | assert!(!package.is_international()); 62 | } 63 | 64 | #[test] 65 | fn calculate_transport_fees() { 66 | let sender_country = String::from("Spain"); 67 | let recipient_country = String::from("Spain"); 68 | 69 | let cents_per_gram = 3000; 70 | 71 | let package = Package::new(sender_country, recipient_country, 1500); 72 | 73 | assert_eq!(package.get_fees(cents_per_gram), 4500); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/tests/README.md: -------------------------------------------------------------------------------- 1 | # Tests 2 | 3 | ## Further information 4 | 5 | * [Writing Tests](https://doc.rust-lang.org/book/ch11-01-writing-tests.html) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/tests/tests1.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn you_can_assert() { 5 | assert!(true); 6 | } 7 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/tests/tests2.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn you_can_assert_eq() { 5 | let a = 1+1; 6 | let b = 2; 7 | assert_eq!(a, b); 8 | } 9 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/tests/tests3.rs: -------------------------------------------------------------------------------- 1 | pub fn is_even(num: i32) -> bool { 2 | num % 2 == 0 3 | } 4 | 5 | #[cfg(test)] 6 | mod tests { 7 | use super::*; 8 | 9 | #[test] 10 | fn is_true_when_even() { 11 | assert!(is_even(4)); 12 | } 13 | 14 | #[test] 15 | fn is_false_when_odd() { 16 | assert!(is_even(5)); 17 | } 18 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/threads/README.md: -------------------------------------------------------------------------------- 1 | # Threads 2 | 3 | ## Further information 4 | 5 | * [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html) 6 | * [Using Threads to Run Code Simultaneously](https://doc.rust-lang.org/book/ch16-01-threads.html) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/threads/threads1.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{Arc, Mutex}; 2 | use std::thread; 3 | use std::time::Duration; 4 | use std::thread::sleep; 5 | 6 | struct JobStatus { 7 | jobs_completed: i32, 8 | } 9 | 10 | fn main() { 11 | // Arc::new : 多线程,保证数据原子性 12 | // Mutex::new : 互斥锁,保证多线程数据安全 13 | let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 })); 14 | let status_shared = status.clone(); 15 | thread::spawn(move || { 16 | for _ in 0..10 { 17 | sleep(Duration::from_millis(250)); 18 | status_shared.lock().unwrap().jobs_completed += 1; 19 | } 20 | }); 21 | 22 | while status.lock().unwrap().jobs_completed < 10 { 23 | println!("waiting..."); 24 | sleep(Duration::from_millis(500)); 25 | } 26 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/traits/README.md: -------------------------------------------------------------------------------- 1 | # Traits 2 | 3 | 特征是方法的集合。 4 | 5 | 数据类型(`struct`) 可以实现特征(`trait`)。为此,为数据类型定义了构成特征的方法。例如,`String`类型实现了 `From<&str> trait`,允许用户编写 `String::from("hello")` 6 | 7 | 一些额外的常见Rust特征包括: 8 | 9 | * `Clone`:`clone`方法。 10 | * `Display`:允许通过 `{}`进行格式化显示。 11 | * `Debug`:允许通过 `{:?}` 进行格式化显示。 12 | 13 | 因为特征(`trait`)指示数据类型之间的共享行为,所以它们在编写泛型时很有用。 14 | 15 |   16 | 17 | ## Further information 18 | 19 | * [traits](https://doc.rust-lang.org/book/ch10-02-traits.html) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/traits/traits1.rs: -------------------------------------------------------------------------------- 1 | trait AppendBar { 2 | fn append_bar(self) -> Self; 3 | } 4 | 5 | impl AppendBar for String { 6 | fn append_bar(self) -> Self { 7 | let mut s:Self = self; 8 | s.push_str("Bar"); 9 | s 10 | } 11 | } 12 | 13 | fn main() { 14 | let s = String::from("Foo"); 15 | let s = s.append_bar(); 16 | println!("s: {}", s); 17 | } 18 | 19 | #[cfg(test)] 20 | #[allow(non_snake_case)] 21 | mod tests { 22 | use super::*; 23 | 24 | #[test] 25 | fn is_FooBar() { 26 | assert_eq!(String::from("Foo").append_bar(), String::from("FooBar")); 27 | } 28 | 29 | #[test] 30 | fn is_BarBar() { 31 | assert_eq! ( 32 | String::from("").append_bar().append_bar(), 33 | String::from("BarBar") 34 | ); 35 | } 36 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/traits/traits2.rs: -------------------------------------------------------------------------------- 1 | trait AppendBar { 2 | fn append_bar(self) -> Self; 3 | } 4 | 5 | impl AppendBar for Vec { 6 | fn append_bar(self) -> Self { 7 | let mut v:Self = self; 8 | v.push("Bar".to_string()); 9 | v 10 | } 11 | } 12 | 13 | #[cfg(test)] 14 | mod tests { 15 | use super::*; 16 | 17 | #[test] 18 | fn is_vec_pop_eq_bar() { 19 | let mut foo = vec![String::from("Foo")].append_bar(); 20 | assert_eq!(foo.pop().unwrap(), String::from("Bar")); 21 | assert_eq!(foo.pop().unwrap(), String::from("Foo")); 22 | } 23 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/variables/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Variables 3 | 4 | 在Rust中,变量默认是只读的。当变量readonly时,一旦将值绑定到名称,就无法更改该值。可以通过在变量名称前添加 `mut` 使它们可变。 5 | 6 | ## Further information 7 | 8 | * [Variables and Mutability](https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html) -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/variables/variables1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let x = 5; 3 | println!("x has the value {}", x); 4 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/variables/variables2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let x:i32 = 0; 3 | if x == 10 { 4 | println!("Ten!"); 5 | } else { 6 | println!("No ten!"); 7 | } 8 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/variables/variables3.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut x = 3; 3 | println!("Number {}", x); 4 | x = 5; 5 | println!("Number {}", x); 6 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/variables/variables4.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let x: i32 = 0x64; 3 | println!("Number {}", x); 4 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/variables/variables5.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let number = "T-H-R-E-E"; 3 | println!("Spell a Number: {}", number); 4 | let number = 3; 5 | println!("Number plus two is: {}", number + 2); 6 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/exercises/variables/variables6.rs: -------------------------------------------------------------------------------- 1 | const NUMBER:i32 = 3; 2 | 3 | fn main() { 4 | println!("Number {}", NUMBER); 5 | } -------------------------------------------------------------------------------- /Rust学习笔记_库/日志/README.md: -------------------------------------------------------------------------------- 1 | # 日志 2 | 3 | 任何中等规模的项目都应该在开发的最初阶段提供日志记录的支持。 4 | 5 |   6 | 7 | ## 日志的重要性 8 | 9 | 能够从应用程序日志记录中获益良多的用户大致分为3类: 10 | 11 | * 系统管理员:他们需要监视服务器日志中的任何故障,例如磁盘崩溃或网络故障。 12 | * 开发人员:在开发过程中,将日志集成到项目中有助于缩短开发时间,后续还可以深入了解用户和应用程序的交互方式。 13 | * 网络安全团队:在远程服务器遭受任何攻击的情况下,安全人员可以从日志记录中获益,因为他们可以通过跟踪被攻击服务器记录的事件日志来了解攻击是如何执行的。 14 | 15 |   16 | 17 | ## 日志记录框架的特性 18 | 19 | * 快速:日志记录框架必须确保它们在记录日志时不会执行开销昂贵的操作,并且应该尽可能少使用CPU时钟周期进行高效处理。 20 | * 可配置的输出:仅将消息记录输出到标准输出是非常局限的。日志记录框架应该能够支持多个输出,例如文件,甚至是网络套接字。 21 | * 日志分级:日志分级是一个可配置的过滤器,通常实现为在将日志输出发送到任何地方之前检查其类型。分级通常按照以下顺序排列,从最高优先级到最低优先级。 22 | 23 | * 错误:此级别适用于记录关键事件,以及可能导致应用程序无效输出的事件。 24 | * 警告:此级别适用于你已经执行评估的事件,以及希望知道何时发生时,如果它们频繁发生,则采取相应措施。 25 | * 信息:此级别用于正常的事件。 26 | * 调试:此级别用于处理调试,用于监视变量的值,以及在调试时在不同的代码路径中操作它们。 27 | * 跟踪:当你希望逐行执行算法或者编写的某个特定函数时,可采用此级别。 28 | * 日志过滤:通常记录日志的特定位置,并根据事件的严重性/重要性来关闭其他日志。 29 | * 日志轮换:日志记录框架应该提供限制日志文件大小的功能,并允许删除较旧的日志文件。 30 | * 异步日志记录:主线程的日志记录调用可能会阻塞其他代码的运行。即使搞笑的记录器尽可能少地占用资源,它仍然会在实际代码之间阻塞I/O调用。因此,用户希望将大多数日志记录调用转移到专用的记录器线程。 31 | * 日志消息属性:日志框架至少应该提供一些属性来记录消息。 32 | 33 | * 时间戳:事件发生的时间。 34 | * 日志级别:消息的重要性级别,例如错误、警告、信息及调试 35 | * 事件位置:事件在源代码中发生的位置 36 | * 消息:描述发生实际事件的消息 37 | 38 |   39 | 40 | ## 日志记录方法 41 | 42 | 日志记录方法大致分为: 非结构化日志记录和结构化日志记录。 43 | 44 |   45 | 46 | ### 非结构化日志 47 | 48 | 处理日志的常见做法是将事件记录作为纯文本字符串,并将所需的任意字段值推送到日志消息中,方法是将这些字段值转成字符串。 49 | 50 | 这种非结构化日志记录适用于大多数用例,它们没有任何可预测的格式,日志集合中检索可能非常麻烦。你需要编写匹配大量文本的正则表达式,或者在命令行用grep来获取特定事件。随着日志数量增加,这种方法最终成为日志文件获取用户信息的瓶颈。 51 | 52 |   53 | 54 | ### 结构化日志 55 | 56 | 结构化日志记录定义了日志消息的结构和格式,并且每个日志消息都确保具有此格式。优势就是,日志聚合服务很容易构建索引,并向用户呈现特定事件,而不用管它们具有多少消息。 57 | 58 | 结构化日志记录不足在于,将它集成到应用程序可能需要花费一些时间,因为必须事先确定日志的层次结构和格式。 59 | -------------------------------------------------------------------------------- /Rust学习笔记_库/日志/rust日志记录.md: -------------------------------------------------------------------------------- 1 | # Rust 日志记录 2 | 3 | Rust中有很多灵活、可扩展的日志记录解决方案。Rust中日志记录生态系统分为两个部分。 4 | 5 | * 日志记录外观: 此部分由 `log` 软件包实现,并提供与实现无关的日志记录API。这些日志记录API按日志级别进行分类,以便将日志记录输出到预配置的目标上。 6 | 7 | * 日志记录实现:可以根据输出的位置和事件发生的方式提供实际的日志记录实现。例如:env_logger、imple_logger、log4rs及fern。 8 | 9 | 日志记录API和日志记录输出的底层机制之间是分离的,开发人员不需要在代码中更改其日志语句,可以根据需要轻松地切换基本的日志记录实现。 10 | 11 |   12 | 13 | ## log 14 | 15 | `log` 软件包提供了单独的宏来记录不同的日志级别,例如 `error!`、`warn!`、`info!`、`debug!` 及 `trace!`。这些宏是该软件包用户的主要交互点,他们在内部会调用此软件包的 `log` 宏,以便执行所有日志记录操作。 16 | 17 | `log` 软件包还提供了一个名为 `STATIC_MAX_LEVEL` 的最大日志级别常量,可以在编译期于项目范围内配置。通过该常量可以使用 cargo 特性标记来设置应用程序的日志级别,这允许对应用程序及所有依赖项的日志进行编译期过滤。你可以使用编译器日志级别指定 `log` 程序库依赖关系。 18 | 19 | ```toml 20 | [dependencies] 21 | log = { version = "0.4.6", features = ["release_max_level_error", "max_level_trace"]} 22 | ``` 23 | 24 |   25 | 26 | ### log 和 env_logger 实例 27 | 28 |   29 | 30 | #### log_为Rust日志记录提供外观 31 | 32 | 创建日志程序库。 33 | 34 | ```bash 35 | bash$ cargo new user_auth --lib 36 | 37 | ``` 38 | 39 |   40 | 41 | 使用 `log` 作为日志提供外观。 42 | 43 | ```toml 44 | # user_auth/Cargo.toml 45 | 46 | [dependencies] 47 | log = "0.4.6" 48 | ``` 49 | 50 | #### env_logger 51 | 52 | 使用 env_logger 软件包实现日志的记录,它允许通过环境变量RUST_LOG将日志输出到stdout或stderr。 53 | 54 | ```bash 55 | bash$ cargo new env_logger_demo 56 | ``` 57 | 58 |   59 | 60 | 配置 `Cargo.toml` 文件,使用log lib库。 61 | 62 | ```toml 63 | # env_logger_demo/Cargo.toml 64 | 65 | [dependencies] 66 | env_logger = "0.6.0" 67 | user_auth = { path = "../user_auth" } 68 | log = { version = "0.4.6", features = ["release_max_level_error", "max_level_trace"]} 69 | ``` 70 | 71 | ```rust 72 | // env_logger_demo/src/main.rs 73 | 74 | use log::debug; 75 | use user_auth::User; 76 | 77 | fn main() { 78 | env_logger::init(); 79 | debug!("env logger demo started"); 80 | let user = User::new("bob", "super_sekret"); 81 | user.sign_in("super_secret"); 82 | user.sign_in("super_sekret"); 83 | } 84 | ``` 85 | 86 | ```bash 87 | root@8d75790f92f5:~/rs/env_logger_demo/src# RUST_LOG=user_auth=info,env_logger_demo=info cargo r 88 | Finished dev [unoptimized + debuginfo] target(s) in 0.21s 89 | Running `/root/rs/env_logger_demo/target/debug/env_logger_demo` 90 | [2021-08-27T02:19:10Z INFO user_auth] Signing in user: bob 91 | [2021-08-27T02:19:10Z ERROR user_auth] Login failed for user: bob 92 | ``` 93 | 94 | 我们将 `user_auth` 设置为info级别,将 `env_logger_demo` 软件包的日志记录设置为 debug 级别。 95 | 96 | RUST_LOG接受 `RUST_LOG=path::to_module=log_level[,]` 模式,其中 `path::to_module` 用于指定记录器,并且以软件包为基础的任何模块的路径。 `log_level`是日志软件包中定义的日志级别。 97 | 98 | 运行上述程序还可以使用 `env` 模块中的 `set_var` 方法设置环境变量进行使用: 99 | 100 | ```rust 101 | use std::env::set_var; 102 | use log::debug; 103 | use user_auth::User; 104 | 105 | fn main() { 106 | set_var("RUST_LOG", "user_auth=info,env_logger_demo=info cargo run"); 107 | env_logger::init(); 108 | debug!("env logger demo started"); 109 | let user = User::new("bob", "super_sekret"); 110 | user.sign_in("super_secret"); 111 | user.sign_in("super_sekret"); 112 | } 113 | ``` 114 | -------------------------------------------------------------------------------- /Rust学习笔记_库/日志/rust日志记录_log4rs.md: -------------------------------------------------------------------------------- 1 | # log4rs 2 | 3 | 相比 `env_logger` 软件包,`log4rs` 软件包要比它强大的多。允许用户通过YAML文件进行细粒度的记录配置。 4 | 5 |   6 | 7 | ## 使用log4rs 8 | 9 | ### 工作空间 10 | 11 | 使用log4rs之前,首先创建一个项目的工作空间。 12 | 13 | ```bash 14 | # 创建工作空间 15 | bash$ mkdir log4rs_demo 16 | bash$ cd log4rs_demo 17 | 18 | # 创建多个包 19 | bash$ cargo new my_lib --lib 20 | bash$ cargo new my_app 21 | 22 | # 创建工作空间配置,添加包成员 23 | bash$ cat > Cargo.toml << end 24 | [workspace] 25 | members = ["my_lib", "my_app"] 26 | end 27 | ``` 28 | 29 |   30 | 31 | ### my_lib 32 | 33 | `my_lib` 有一个名为 Config 的结构体,包含了一个名为 `load_global_config` 方法,它在 `debug` 级别记录日志消息。 34 | 35 | ```rust 36 | // log4rs_demo/my_lib/src/lib.rs 37 | 38 | use log::debug 39 | 40 | pub struct Config; 41 | impl Config { 42 | pub fn load_global_config() { 43 | debug!("Configuration files loaded"); 44 | } 45 | } 46 | ``` 47 | 48 |   49 | 50 | `my_lib` 包的 `Cargo.toml` 配置: 51 | 52 | ```toml 53 | # log4rs_demo/my_lib/Cargo.toml 54 | 55 | [dependencies] 56 | log = "0.4.8" 57 | ``` 58 | 59 |   60 | 61 | ### my_app 62 | 63 | ```rust 64 | // log4rs_demo/my_app/src/main.rs 65 | 66 | use log::error; 67 | 68 | use my_lib::Config; 69 | 70 | fn main() { 71 | // 通过init_file方法初始化log4rs记录器,并将路径传递给 log4rs.yaml 配置文件 72 | log4rs::init_file("config/log4rs.yaml", Default::default()).unwrap(); 73 | error!("Sample app v{}", env!("CARGO_PKG_VERSION")); 74 | Config::load_global_config(); 75 | } 76 | ``` 77 | 78 | ```toml 79 | # log4rs_demo/my_app/Cargo.toml 80 | 81 | [dependencies] 82 | my_lib = { path = "../my_lib" } 83 | log = "0.4.8" 84 | log4rs = "0.10.0" 85 | ``` 86 | 87 |   88 | 89 | #### 加载log4rs.yaml 配置文件 90 | 91 | ```yaml 92 | refresh_rate: 5 seconds 93 | 94 | appenders: 95 | stdout: 96 | kind: console 97 | my_lib_append: 98 | kind: file 99 | path: "log/my_lib.log" 100 | encoder: 101 | pattern: "{d} - {m}{n}" 102 | 103 | root: 104 | level: error 105 | appenders: 106 | - stdout 107 | 108 | loggers: 109 | my_lib: 110 | level: debug 111 | appenders: 112 | - my_lib_append 113 | ``` 114 | 115 |   116 | 117 | 如上配置解析: 118 | 119 | * refresh_rate: 重新加载该yaml文件时间间隔 120 | * root: 根记录器,它是所有记录器的父记录器 121 | * appenders: 输出源 122 | * stdout: 控制台输出源类型 123 | * my_lib_append: 自定义输出源类型 124 | * loggers: 日志记录器 125 | * my_lib: 自定义日志记录器,它用于适配`my_lib`软件包 126 | * level: 日志级别为 127 | * appenders: 输出源 128 | 129 |   130 | 131 | ### 执行结果 132 | 133 | ```bash 134 | root@8d75790f92f5:~/rs/log4rs# cargo r 135 | Finished dev [unoptimized + debuginfo] target(s) in 0.40s 136 | Running `target/debug/my_app` 137 | 2021-08-28T11:55:40.448922+08:00 ERROR my_app - Sample app v0.1.0 138 | 2021-08-28T11:55:40.449751500+08:00 DEBUG my_lib - Configuration files loaded 139 | ``` 140 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /imgs/gcc_rust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/imgs/gcc_rust.png -------------------------------------------------------------------------------- /imgs/rust-for-linux.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/imgs/rust-for-linux.jpg -------------------------------------------------------------------------------- /imgs/rust_01.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/imgs/rust_01.jpeg -------------------------------------------------------------------------------- /linux-cves-in-2018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/linux-cves-in-2018.png -------------------------------------------------------------------------------- /png-transparent-rust-programming-language-logo-machine-learning-haskell-crab-animals-cartoon-crab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/png-transparent-rust-programming-language-logo-machine-learning-haskell-crab-animals-cartoon-crab.png -------------------------------------------------------------------------------- /rust.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rust_board.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/rust_board.png -------------------------------------------------------------------------------- /rust_facebook.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/rust_facebook.jpeg -------------------------------------------------------------------------------- /rust_language.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/rust_language.jpeg -------------------------------------------------------------------------------- /rust_playground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/rust_playground.png -------------------------------------------------------------------------------- /wechat.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuesongbj/Rust-Notes/35057fe4b14f606325c2a1ad1d37e03ec18fad61/wechat.jpeg --------------------------------------------------------------------------------