├── .github └── ISSUE_TEMPLATE │ └── corrigendum.md ├── .gitignore ├── Cargo.toml ├── LICENSE-MIT ├── README.md ├── audios └── .keep ├── images ├── 0.png ├── 1.png ├── 2.png ├── run.png ├── rustbook.bk.jpg ├── rustbook.jpg └── toc.png ├── src ├── appendix │ ├── .gitignore │ ├── lldb.rs │ └── mod.rs ├── ch01 │ └── mod.rs ├── ch02 │ ├── annotation.rs │ ├── binding.rs │ ├── collections.rs │ ├── control_flow.rs │ ├── enums.rs │ ├── errors_handle.rs │ ├── function.rs │ ├── generics_trait.rs │ ├── mod.rs │ ├── primitives.rs │ ├── smart_pointer.rs │ └── structs.rs ├── ch03 │ ├── abstract_type.rs │ ├── bottom_type.rs │ ├── generics.rs │ ├── mod.rs │ ├── tag_trait.rs │ ├── trait_limit.rs │ ├── traits.rs │ ├── type_cast.rs │ ├── type_infer.rs │ ├── type_size.rs │ └── zero_size.rs ├── ch04 │ ├── general_concepts.rs │ ├── memory_leak.rs │ ├── mod.rs │ ├── raii.rs │ └── resource_management.rs ├── ch05 │ ├── borrow.rs │ ├── lifetime.rs │ ├── mod.rs │ ├── nll.rs │ ├── semantic.rs │ ├── share_mutable.rs │ └── smart_pointer.rs ├── ch06 │ ├── closures.rs │ ├── functions.rs │ ├── iters.rs │ └── mod.rs ├── ch07 │ ├── design_pattern.rs │ ├── mod.rs │ └── structs.rs ├── ch08 │ ├── bases.rs │ ├── hashmaps.rs │ ├── mod.rs │ ├── strings.rs │ └── vectors.rs ├── ch09 │ ├── errors.rs │ ├── examples │ │ ├── io_origin.rs │ │ ├── io_origin_refactor.rs │ │ ├── io_origin_refactor3.rs │ │ ├── io_origin_refactor4.rs │ │ └── test_txt │ ├── failures.rs │ ├── failures_crate │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src │ │ │ ├── lib.rs │ │ │ ├── main.rs │ │ │ └── text_test │ ├── mod.rs │ └── panics.rs ├── ch10 │ ├── csv-read │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── csv_challenge │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── README.md │ │ ├── benches │ │ │ └── file_op_bench.rs │ │ ├── input │ │ │ ├── challenge.csv │ │ │ └── no_header.csv │ │ ├── output │ │ │ ├── output.csv │ │ │ └── test.csv │ │ ├── src │ │ │ ├── core.rs │ │ │ ├── core │ │ │ │ ├── read.rs │ │ │ │ └── write.rs │ │ │ ├── err.rs │ │ │ ├── lib.rs │ │ │ ├── main.rs │ │ │ └── opt.rs │ │ └── tests │ │ │ └── integration_test.rs │ ├── mod.rs │ ├── static_hashmap │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── static_hashmap_2015 │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── main.rs │ │ │ └── static_func │ │ │ ├── mod.rs │ │ │ ├── read_func.rs │ │ │ └── static_kv.rs │ ├── static_hashmap_2018 │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── main.rs │ │ │ ├── read_func.rs │ │ │ └── read_func │ │ │ └── static_kv.rs │ ├── tt │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── bar.rs │ │ │ ├── foo.rs │ │ │ ├── foo │ │ │ └── hello.rs │ │ │ └── main.rs │ ├── use_regex │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ └── visibility.rs ├── ch11 │ ├── atomics.rs │ ├── channels.rs │ ├── crossbeam.rs │ ├── futures-demo │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── generator.rs │ ├── mod.rs │ ├── pow │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── rayon.rs │ ├── simd-demo │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src │ │ │ ├── auto_vector.rs │ │ │ ├── faster_main.rs │ │ │ └── main.rs │ ├── thread_management.rs │ ├── thread_pool │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── thread_sync.rs │ └── thread_unsafe.rs ├── ch12 │ ├── derive-new │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── lib.rs │ │ └── tests │ │ │ └── test.rs │ ├── hashmap_lite │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src │ │ │ ├── lib.rs │ │ │ └── main.rs │ ├── macros.rs │ ├── mod.rs │ ├── plugin_demo │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── lib.rs │ │ └── tests │ │ │ └── test.rs │ ├── reflect.rs │ └── simple_proc_macro │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── src │ │ └── lib.rs │ │ └── tests │ │ └── test.rs ├── ch13 │ ├── callrust │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── Node.js │ │ │ └── database.js │ │ ├── Python │ │ │ └── database.py │ │ ├── Ruby │ │ │ └── database.rb │ │ ├── c_src │ │ │ └── main.c │ │ ├── makefile │ │ └── src │ │ │ ├── callrust.h │ │ │ └── lib.rs │ ├── ffi.rs │ ├── global_alloc.rs │ ├── hello_wasm │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── README.md │ │ ├── hello.html │ │ ├── hello.js │ │ ├── output │ │ │ ├── .keep │ │ │ ├── hello_wasm.wasm │ │ │ └── small_hello.wasm │ │ └── src │ │ │ └── lib.rs │ ├── mod.rs │ ├── non_null_pointer.rs │ ├── panic_safety.rs │ ├── raw_pointer.rs │ ├── rustcallcapp │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── build.rs │ │ ├── cpp_src │ │ │ ├── sorting.cpp │ │ │ └── sorting.h │ │ └── src │ │ │ └── main.rs │ ├── security_abstract.rs │ ├── unsafe_intro.rs │ ├── wasm-bindgen-demo │ │ ├── .appveyor.yml │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── Cargo.toml │ │ ├── LICENSE_APACHE │ │ ├── LICENSE_MIT │ │ ├── README.md │ │ ├── define.js │ │ ├── index.js │ │ ├── package.json │ │ ├── src │ │ │ ├── lib.rs │ │ │ └── utils.rs │ │ ├── tests │ │ │ └── web.rs │ │ ├── wasm_bindgen_demo.d.ts │ │ ├── wasm_bindgen_demo.js │ │ ├── wasm_bindgen_demo_bg.wasm │ │ └── webpack.config.js │ └── wasm.rs └── lib.rs └── tao_of_rust_english.md /.github/ISSUE_TEMPLATE/corrigendum.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: corrigendum 3 | about: 勘误模板 4 | 5 | --- 6 | 7 | # 页码与行数 8 | 9 | - 第1页 10 | - 第2行 11 | 12 | --- 13 | 14 | # 文本或排版错误 15 | 16 | > 暂无 17 | 18 | --- 19 | 20 | # 代码错误 21 | 22 | ```rust 23 | let a = "hello"; // 此处应该是hello world 24 | ``` 25 | ### Rust版本 26 | 27 | ``` 28 | $ rustc -V 29 | rustc 1.32.0-nightly (8b096314a 2018-11-02) 30 | ``` 31 | 32 | ### 错误信息 33 | 34 | ```rust 35 | error: xxxx 36 | xxxx 37 | xxxx 38 | ``` 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode 7 | /debug 8 | /doc 9 | .rustc_info.json -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tao-of-rust" 3 | version = "1.0.2" 4 | authors = ["blackanger "] 5 | description = "《Rust编程之道》随书源码" 6 | homepage = "https://github.com/ZhangHanDong/tao-of-rust-codes" 7 | documentation = "https://docs.rs/crate/tao-of-rust/" 8 | repository = "https://github.com/ZhangHanDong/tao-of-rust-codes" 9 | license = "MIT" 10 | keywords = ["book"] 11 | categories = ["rust-programming-book-codes"] 12 | readme = "README.md" 13 | 14 | [dependencies] 15 | failures_crate = { version = "0.1", path = "./src/ch09/failures_crate" } 16 | csv_challenge = { version = "0.1", path = "./src/ch10/csv_challenge" } 17 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) 2 | [![crates.io](https://meritbadge.herokuapp.com/tao-of-rust)](https://crates.io/crates/tao-of-rust) 3 | [![Released API docs](https://docs.rs/tao-of-rust/badge.svg)](https://docs.rs/tao-of-rust) 4 | 5 | ### English Version 6 | 7 | [The Tao of Rust: Table of Contents](./tao_of_rust_english.md) 8 | 9 | ### 豆瓣书评 10 | 11 | 希望大家看完之后,可以给个评价。 12 | 13 | [《Rust编程之道》豆瓣书评](https://book.douban.com/subject/30418895/) 14 | 15 | ### 购买地址:各大电商平台 16 | 17 | - [电子工业出版社京东店](https://item.jd.com/12479415.html) 18 | 19 | 20 | --- 21 | 22 | ![img4](images/rustbook.jpg) 23 | 24 | # 《Rust编程之道》随书源码 25 | 26 | 本书现在已出版。 27 | 28 | **跟进Rust 2018最新特性!!** 29 | 30 | **跟进Rust 2018最新特性!!** 31 | 32 | **跟进Rust 2018最新特性!!** 33 | 34 | 说明:本仓库代码暂时不接受任何PR,因为很多都是随书源码案例,其中代码有专门的演示作用。如有异议,可以提交issues讨论。 35 | 36 | _注意:本书代码的平台是Linux或macOS_ 37 | 38 | ### 书籍勘误说明 39 | 40 | 1. 提交issues 41 | 2. 表明具体的「页码」、「行数」和「出错」信息 42 | 3. 积极勘误者将获得Rust勋章一枚 43 | 44 | ### Rust版本依赖: 45 | 46 | - `Rust stable 1.31.0 + ` 47 | - `Rust Nightly 1.31.0 +` 48 | 49 | 输出文档时指定target目录: 50 | 51 | ``` 52 | $ cargo doc --target-dir ./ 53 | ``` 54 | 55 | ### 使用说明: 56 | 57 | ```shell 58 | $ git clone https://github.com/ZhangHanDong/tao-of-rust-codes.git 59 | $ cd tao-of-rust-codes 60 | $ cargo doc 61 | $ open target/doc/tao_of_rust/index.html 62 | ``` 63 | 64 | 在线阅读: 65 | 66 | - [在线GitHub Page在线文档](https://ruststudy.github.io/tao_of_rust_docs/tao_of_rust/) 67 | 68 | or: 69 | 70 | - 在线阅读[docs.rs/tao-of-rust](https://docs.rs/tao-of-rust/1.0.1/tao_of_rust/) 71 | 72 | ### 图示 73 | 74 | ![img1](images/0.png) 75 | ![img2](images/1.png) 76 | ![img3](images/2.png) 77 | 78 | 点击Run,跳转到[play.rust-lang.org](https://play.rust-lang.org) 79 | ![img4](images/run.png) 80 | 81 | ### 本书完整目录 82 | 83 | ![TOC](images/toc.png) 84 | -------------------------------------------------------------------------------- /audios/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhangHanDong/tao-of-rust-codes/49d8be60c01b8900e71941d0349825e08453e557/audios/.keep -------------------------------------------------------------------------------- /images/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhangHanDong/tao-of-rust-codes/49d8be60c01b8900e71941d0349825e08453e557/images/0.png -------------------------------------------------------------------------------- /images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhangHanDong/tao-of-rust-codes/49d8be60c01b8900e71941d0349825e08453e557/images/1.png -------------------------------------------------------------------------------- /images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhangHanDong/tao-of-rust-codes/49d8be60c01b8900e71941d0349825e08453e557/images/2.png -------------------------------------------------------------------------------- /images/run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhangHanDong/tao-of-rust-codes/49d8be60c01b8900e71941d0349825e08453e557/images/run.png -------------------------------------------------------------------------------- /images/rustbook.bk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhangHanDong/tao-of-rust-codes/49d8be60c01b8900e71941d0349825e08453e557/images/rustbook.bk.jpg -------------------------------------------------------------------------------- /images/rustbook.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhangHanDong/tao-of-rust-codes/49d8be60c01b8900e71941d0349825e08453e557/images/rustbook.jpg -------------------------------------------------------------------------------- /images/toc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhangHanDong/tao-of-rust-codes/49d8be60c01b8900e71941d0349825e08453e557/images/toc.png -------------------------------------------------------------------------------- /src/appendix/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | .DS_Store 5 | lldb 6 | .vscode/ 7 | rls/ -------------------------------------------------------------------------------- /src/appendix/lldb.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | use std::fmt; 3 | 4 | pub struct Packet 5 | { 6 | pub payload: VecDeque, 7 | } 8 | 9 | pub struct Header 10 | { 11 | pub data: Vec, 12 | } 13 | 14 | impl Packet 15 | { 16 | pub fn new() -> Self 17 | { 18 | let payload = VecDeque::with_capacity(32); 19 | Packet{payload} 20 | } 21 | 22 | pub fn len(&self) -> usize 23 | { 24 | self.payload.len() 25 | } 26 | 27 | pub fn push_header(&mut self, header: &Header) 28 | { 29 | self.payload.reserve(header.data.len()); 30 | for b in header.data.iter().rev() { 31 | self.payload.push_front(*b); 32 | } 33 | } 34 | 35 | pub fn push_back_bytes(&mut self, data: &[u8]) 36 | { 37 | self.payload.extend(data.iter()); 38 | } 39 | } 40 | 41 | impl fmt::Debug for Packet 42 | { 43 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result 44 | { 45 | let mut bytes = String::with_capacity(3*self.len()); 46 | for i in 0..self.payload.len() { 47 | bytes.push_str(&format!(" {:02X}", self.payload[i])); 48 | } 49 | 50 | write!(f, "{}", bytes) 51 | } 52 | } 53 | 54 | impl Header 55 | { 56 | pub fn new() -> Self 57 | { 58 | let data = Vec::with_capacity(20); 59 | Header{data} 60 | } 61 | 62 | pub fn with_capacity(capacity: usize) -> Self 63 | { 64 | let data = Vec::with_capacity(capacity); 65 | Header{data} 66 | } 67 | 68 | pub fn push8(&mut self, data: u8) 69 | { 70 | self.data.push(data); 71 | } 72 | 73 | pub fn push16(&mut self, data: u16) 74 | { 75 | self.data.push((data >> 8) as u8); 76 | self.data.push((data & 0xFF) as u8); 77 | } 78 | 79 | pub fn push32(&mut self, data: u32) 80 | { 81 | self.data.push((data >> 24) as u8); 82 | self.data.push(((data >> 16) & 0xFF) as u8); 83 | self.data.push(((data >> 8) & 0xFF) as u8); 84 | self.data.push((data & 0xFF) as u8); 85 | } 86 | 87 | pub fn push_bytes(&mut self, data: &[u8]) 88 | { 89 | self.data.extend(data); 90 | } 91 | } 92 | 93 | pub fn push_ipv4(packet: &mut Packet) 94 | { 95 | let payload_len = packet.len(); 96 | let mut header = Header::with_capacity(20); 97 | 98 | let b = 0x45; // version + IHL (we don't support options so length is fixed) 99 | header.push8(b); 100 | 101 | header.push8(20); 102 | 103 | let hw = 20 + payload_len; // total length 104 | header.push16(hw as u16); 105 | 106 | header.push16(21); // identification 107 | header.push16(23); 108 | 109 | packet.push_header(&header); 110 | } 111 | 112 | pub fn push_mac(packet: &mut Packet) 113 | { 114 | let mut header = Header::with_capacity(30); 115 | 116 | let hw = 0b1000_10_00; // frame control, see 9.2.4.1 117 | header.push16(hw); 118 | 119 | let addr = [1, 2, 3, 4, 5, 6]; 120 | for &b in addr.iter() { // address 1, see 9.3.2.1 121 | header.push8(b); 122 | } 123 | 124 | for &b in addr.iter() { // address 2 125 | header.push8(b); 126 | } 127 | 128 | for &b in addr.iter() {// address 3 129 | header.push8(b); 130 | } 131 | 132 | header.push16(55); 133 | 134 | let hw = 0b111_0_00_0_000; // QoS control, see 9.2.4.5.1 135 | header.push16(hw); 136 | 137 | packet.push_header(&header); 138 | 139 | let fcs = [0xD9, 0x58, 0xFB, 0xA8]; 140 | println!("old packet = {:?}", packet); 141 | println!("pushing {:X} {:X} {:X} {:X} ", fcs[0], fcs[1], fcs[2], fcs[3]); 142 | packet.push_back_bytes(&fcs); 143 | 144 | println!("new packet = {:?}", packet); 145 | } 146 | 147 | fn main() 148 | { 149 | let mut packet = Packet::new(); 150 | push_ipv4(&mut packet); 151 | push_mac(&mut packet); 152 | } 153 | -------------------------------------------------------------------------------- /src/appendix/mod.rs: -------------------------------------------------------------------------------- 1 | //! 附录表: 2 | //! 3 | //! # rust-lldb debug示例 4 | //! 5 | //! 命令: 6 | //! ```rust 7 | //! $ sudo rust-lldb ./lldb 8 | //! ``` 9 | //! 10 | //! 调试命令: 11 | //! - b main // 设置断点 12 | //! - r // 执行程序 13 | //! - c // 继续执行 14 | 15 | 16 | fn hello(){ 17 | println!("新时代的语言:{}", "Rust"); 18 | } 19 | 20 | pub mod lldb; 21 | -------------------------------------------------------------------------------- /src/ch01/mod.rs: -------------------------------------------------------------------------------- 1 | //! 第一章:新时代的语言 2 | //! 3 | 4 | 5 | /// # Examples 6 | /// 7 | /// Basic usage: 8 | /// 9 | /// ``` 10 | /// pub fn title(){ 11 | /// println!("第1章:{}", "新时代的语言"); 12 | /// } 13 | /// title(); 14 | /// ``` 15 | pub fn title(){ 16 | println!("第1章:{}", "新时代的语言"); 17 | } 18 | 19 | 20 | pub struct Duck; 21 | pub struct Pig; 22 | 23 | pub trait Fly { 24 | fn fly(&self) -> bool; 25 | } 26 | 27 | impl Fly for Duck { 28 | fn fly(&self) -> bool { 29 | return true; 30 | } 31 | } 32 | 33 | impl Fly for Pig { 34 | fn fly(&self) -> bool { 35 | return false; 36 | } 37 | } 38 | /// # 零成本抽象 fly_static 39 | /// 40 | /// ``` 41 | /// struct Duck; 42 | /// struct Pig; 43 | /// 44 | /// trait Fly { 45 | /// fn fly(&self) -> bool; 46 | /// } 47 | /// 48 | /// impl Fly for Duck { 49 | /// fn fly(&self) -> bool { 50 | /// return true; 51 | /// } 52 | /// } 53 | /// impl Fly for Pig { 54 | /// fn fly(&self) -> bool { 55 | /// return false; 56 | /// } 57 | /// } 58 | /// 59 | /// fn fly_static(s: T) -> bool { 60 | /// s.fly() 61 | /// } 62 | /// 63 | /// fn fly_dyn(s: &Fly) -> bool { 64 | /// s.fly() 65 | /// } 66 | /// let pig = Pig; 67 | /// assert_eq!(fly_static::(pig), false); 68 | /// let duck = Duck; 69 | /// assert_eq!(fly_static::(duck), true); 70 | /// ``` 71 | pub fn fly_static(s: T) -> bool { 72 | s.fly() 73 | } 74 | 75 | /// # 零成本抽象 fly_dyn 76 | /// 77 | /// ``` 78 | /// struct Duck; 79 | /// struct Pig; 80 | /// 81 | /// trait Fly { 82 | /// fn fly(&self) -> bool; 83 | /// } 84 | /// 85 | /// impl Fly for Duck { 86 | /// fn fly(&self) -> bool { 87 | /// return true; 88 | /// } 89 | /// } 90 | /// impl Fly for Pig { 91 | /// fn fly(&self) -> bool { 92 | /// return false; 93 | /// } 94 | /// } 95 | /// 96 | /// fn fly_static(s: T) -> bool { 97 | /// s.fly() 98 | /// } 99 | /// 100 | /// fn fly_dyn(s: &Fly) -> bool { 101 | /// s.fly() 102 | /// } 103 | /// assert_eq!(fly_dyn(&Pig), false); 104 | /// assert_eq!(fly_dyn(&Duck), true); 105 | /// ``` 106 | pub fn fly_dyn(s: &Fly) -> bool { 107 | s.fly() 108 | } 109 | -------------------------------------------------------------------------------- /src/ch02/annotation.rs: -------------------------------------------------------------------------------- 1 | /// # 注释 2 | /// 3 | /// Basic usage: 4 | /// 5 | /// ``` 6 | /// /// # 文档注释: Sum函数 7 | /// /// 该函数为求和函数 8 | /// /// # usage: 9 | /// /// assert_eq!(3, sum(1, 2)); 10 | /// fn sum(a: i32, b: i32) -> i32 { 11 | /// a + b 12 | /// } 13 | /// pub fn annotation () { 14 | /// // 这是单行注释的示例 15 | /// /* 16 | /// * 这是区块注释, 被包含的区域都会被注释 17 | /// * 你可以把/* 区块 */ 置于代码中的任何位置 18 | /// */ 19 | /// /* 20 | /// 注意上面区块注释中的*符号,纯粹是一种注释风格, 21 | /// 实际并不需要 22 | /// */ 23 | /// let x = 5 + /* 90 + */ 5; 24 | /// println!("Is `x` 10 or 100? x = {}", x); 25 | /// println!("2 + 3 = {}", sum(2, 3)); 26 | /// } 27 | /// ``` 28 | pub fn annotation() { 29 | // 这是单行注释的示例 30 | /* 31 | * 这是区块注释, 被包含的区域都会被注释 32 | * 你可以把/* 区块 */ 置于代码中的任何位置 33 | */ 34 | /* 35 | 注意上面区块注释中的*符号,纯粹是一种注释风格, 36 | 实际并不需要 37 | */ 38 | let x = 5 + /* 90 + */ 5; 39 | println!("Is `x` 10 or 100? x = {}", x); 40 | println!("2 + 3 = {}", sum(2, 3)); 41 | } 42 | 43 | fn sum(a: i32, b: i32) -> i32 { 44 | a + b 45 | } 46 | -------------------------------------------------------------------------------- /src/ch02/binding.rs: -------------------------------------------------------------------------------- 1 | 2 | /// # 临时值 3 | /// 4 | /// Basic usage: 5 | /// 6 | /// ``` 7 | /// pub fn temp() -> i32 { 8 | /// return 1; 9 | /// } 10 | /// let x = &temp(); 11 | /// temp() = *x; // error[E0070]: invalid left-hand side expression 12 | /// ``` 13 | pub fn temp() -> i32 { 14 | return 1; 15 | } 16 | 17 | /// # 不变与可变 18 | /// 19 | /// Basic usage: 20 | /// 21 | /// ``` 22 | /// pub fn immutable_and_mutable() { 23 | /// let a = 1; // 默认不可变 24 | /// // a = 2; // immutable and error: cannot assign twice to immutable variable 25 | /// let mut b = 2; // 使用mut关键字声明可变绑定 26 | /// b = 3; // mutable 27 | /// } 28 | /// immutable_and_mutable(); 29 | /// ``` 30 | pub fn immutable_and_mutable() { 31 | let a = 1; 32 | // a = 2; // immutable and error 33 | let mut b = 2; 34 | b = 3; // mutable 35 | } 36 | 37 | /// # 所有权 38 | /// 39 | /// Basic usage: 40 | /// 41 | /// ``` 42 | /// pub fn ownership(){ 43 | /// let place1 = "hello"; 44 | /// // ^^ 位置表达式 ^^ 值表达式 45 | /// // ^ 位置上下文 ^ 值上下文 46 | /// let place2 = "hello".to_string(); 47 | /// let other = place1; // Copy 48 | /// // ^^ 位置表达式出现在了值上下文中 49 | /// println!("{:?}", place1); // place1还可以继续使用 50 | /// let other = place2; // Move 51 | /// // ^^ 位置表达式出现在了值上下文中 52 | /// println!("{:?}", place2); // place2不能再被使用,编译出错 53 | /// } 54 | /// ownership(); 55 | /// ``` 56 | pub fn ownership() { 57 | let place1 = "hello"; 58 | let place2 = "hello".to_string(); 59 | let other = place1; 60 | println!("{:?}", other); 61 | let other = place2; 62 | println!("{:?}", place2); // place2 value used here after move 63 | } 64 | 65 | /// # 引用 66 | /// 67 | /// Basic usage: 68 | /// 69 | /// ``` 70 | /// pub fn reference() { 71 | /// let a = [1,2,3]; 72 | /// let b = &a; 73 | /// println!("{:p}", b); // 0x7ffcbc067704 74 | /// let mut c = vec![1,2,3]; 75 | /// let d = &mut c; 76 | /// d.push(4); 77 | /// println!("{:?}", d); 78 | /// let e = &42; 79 | /// assert_eq!(42, *e); 80 | /// } 81 | /// reference(); 82 | /// ``` 83 | pub fn reference() { 84 | let a = [1,2,3]; 85 | let b = &a; 86 | println!("{:p}", b); // 0x7ffcbc067704 87 | let mut c = vec![1,2,3]; 88 | let d = &mut c; 89 | d.push(4); 90 | println!("{:?}", d); // [1, 2, 3, 4] 91 | let e = &42; 92 | assert_eq!(42, *e); 93 | } 94 | -------------------------------------------------------------------------------- /src/ch02/enums.rs: -------------------------------------------------------------------------------- 1 | /// # 枚举类型: 无参数 2 | /// 3 | /// Basic usage: 4 | /// 5 | /// ``` 6 | /// enum Number { 7 | /// Zero, 8 | /// One, 9 | /// Two, 10 | /// } 11 | /// let a = Number::One; 12 | /// match a { 13 | /// Number::Zero => println!("0"), 14 | /// Number::One => println!("1"), 15 | /// Number::Two => println!("2"), 16 | /// } 17 | /// ``` 18 | pub enum Number { 19 | Zero, 20 | One, 21 | Two, 22 | } 23 | 24 | /// # 枚举类型: like C 25 | /// 26 | /// Basic usage: 27 | /// 28 | /// ``` 29 | /// enum Color { 30 | /// Red = 0xff0000, 31 | /// Green = 0x00ff00, 32 | /// Blue = 0x0000ff, 33 | ///} 34 | /// println!("roses are #{:06x}", Color::Red as i32); 35 | /// println!("violets are #{:06x}", Color::Blue as i32); 36 | /// ``` 37 | pub enum Color { 38 | Red = 0xff0000, 39 | Green = 0x00ff00, 40 | Blue = 0x0000ff, 41 | } 42 | 43 | /// # 枚举类型: 带参数 44 | /// 45 | /// Basic usage: 46 | /// 47 | /// ``` 48 | /// enum IpAddr { 49 | /// V4(u8, u8, u8, u8), 50 | /// V6(String), 51 | /// } 52 | /// let f : fn(u8, u8, u8, u8) -> IpAddr = IpAddr::V4; 53 | /// let ff : fn(String) -> IpAddr = IpAddr::V6; 54 | /// let home = IpAddr::V4(127, 0, 0, 1); 55 | /// ``` 56 | pub enum IpAddr { 57 | V4(u8, u8, u8, u8), 58 | V6(String), 59 | } 60 | 61 | /// # 枚举类型:Option 62 | /// 63 | /// Basic usage: 64 | /// 65 | /// ``` 66 | /// enum Option{ 67 | /// Some(i32), 68 | /// None, 69 | /// } 70 | /// let s = Some(42); 71 | /// assert_eq!(s.unwrap(), 42); 72 | /// match s { 73 | /// Some(n) => println!("num is: {}", n), 74 | /// None => (), 75 | /// }; 76 | /// ``` 77 | pub enum MyOption{ 78 | Some(i32), 79 | None, 80 | } 81 | 82 | /// # match 匹配引用 (Rust 2015 用法) 83 | /// 84 | /// Basic usage: 85 | /// 86 | /// ``` 87 | /// fn match_ref_2015() { 88 | /// let s: &Option = &Some("hello".to_string()); 89 | /// match s { 90 | /// &Some(ref s) => println!("s is: {}", s), 91 | /// _ => (), 92 | /// }; 93 | /// } 94 | /// match_ref_2015(); 95 | /// ``` 96 | pub fn match_ref_2015() { 97 | let s: &Option = &Some("hello".to_string()); 98 | match s { 99 | &Some(ref s) => println!("s is: {}", s), 100 | _ => (), 101 | }; 102 | } 103 | 104 | 105 | /// # match 匹配引用 (Rust 2018 用法) 106 | /// 107 | /// Basic usage: 108 | /// 109 | /// ``` 110 | /// fn match_ref_2018() { 111 | /// let s: &Option = &Some("hello".to_string()); 112 | /// match s { 113 | /// Some(s) => println!("s is: {}", s), 114 | /// _ => (), 115 | /// }; 116 | /// } 117 | /// match_ref_2018(); 118 | /// ``` 119 | pub fn match_ref_2018() { 120 | let s: &Option = &Some("hello".to_string()); 121 | match s { 122 | Some(s) => println!("s is: {}", s), 123 | _ => (), 124 | }; 125 | } 126 | -------------------------------------------------------------------------------- /src/ch02/errors_handle.rs: -------------------------------------------------------------------------------- 1 | /// # std::result::Result 定义 2 | /// 3 | /// Basic usage: 4 | /// 5 | /// ``` 6 | /// let x: Result = Ok(-3); 7 | /// assert_eq!(x.is_ok(), true); 8 | /// 9 | /// let x: Result = Err("Some error message"); 10 | /// assert_eq!(x.is_ok(), false); 11 | /// ``` 12 | /// 13 | /// ### Rust 2018 main函数可以返回Result 14 | /// 15 | /// ``` 16 | /// // use std::fs::File; 17 | /// // fn main() -> Result<(), std::io::Error> { 18 | /// // let f = File::open("bar.txt")?; 19 | /// // Ok(()) 20 | /// // } 21 | /// ``` 22 | pub enum Result { 23 | Ok(T), 24 | Err(E), 25 | } 26 | -------------------------------------------------------------------------------- /src/ch02/generics_trait.rs: -------------------------------------------------------------------------------- 1 | /// # std::option::Option 定义 2 | /// 3 | /// Basic usage: 4 | /// 5 | /// ``` 6 | /// use std::fmt::Debug; 7 | /// fn match_option(o: Option) { 8 | /// match o { 9 | /// Some(i) => println!("{:?}", i), 10 | /// None => println!("nothing"), 11 | /// } 12 | /// } 13 | /// let a: Option = Some(3); 14 | /// let b: Option<&str> = Some("hello"); 15 | /// let c: Option = Some('A'); 16 | /// let d: Option = None; 17 | /// 18 | /// match_option(a); // 3 19 | /// match_option(b); // "hello" 20 | /// match_option(c); // 'A' 21 | /// match_option(d); // nothing 22 | /// ``` 23 | pub enum Option{ 24 | Some(T), 25 | None, 26 | } 27 | 28 | /// # trait示例 29 | /// 30 | /// Basic usage: 31 | /// 32 | /// ``` 33 | /// pub trait Fly { 34 | /// fn fly(&self) -> bool; 35 | /// } 36 | /// struct Duck; 37 | /// struct Pig; 38 | /// impl Fly for Duck { 39 | /// fn fly(&self) -> bool { 40 | /// return true; 41 | /// } 42 | /// } 43 | /// impl Fly for Pig { 44 | /// fn fly(&self) -> bool { 45 | /// return false; 46 | /// } 47 | /// } 48 | /// fn fly_static(s: T) -> bool { 49 | /// s.fly() 50 | /// } 51 | /// fn fly_dyn(s: &Fly) -> bool { 52 | /// s.fly() 53 | /// } 54 | /// let pig = Pig; 55 | /// assert_eq!(fly_static::(pig), false); 56 | /// let duck = Duck; 57 | /// assert_eq!(fly_static::(duck), true); 58 | /// assert_eq!(fly_dyn(&Pig), false); 59 | /// assert_eq!(fly_dyn(&Duck), true); 60 | /// ``` 61 | pub trait Fly { 62 | fn fly(&self) -> bool; 63 | } 64 | 65 | /// # impl Debug trait示例 66 | /// 67 | /// Basic usage: 68 | /// 69 | /// ``` 70 | /// use std::fmt::*; 71 | /// struct Point { 72 | /// x: i32, 73 | /// y: i32, 74 | /// } 75 | /// // Debug trait中定义了fmt方法 76 | /// impl Debug for Point { 77 | /// fn fmt(&self, f: &mut Formatter) -> Result { 78 | /// // 使用编译器内置的write!宏来实现 79 | /// write!(f, "Point {{ x: {}, y: {} }}", self.x, self.y) 80 | /// } 81 | /// } 82 | /// let origin = Point { x: 0, y: 0 }; 83 | /// println!("The origin is: {:?}", origin); 84 | /// ``` 85 | pub fn impl_debug_trait(){ 86 | use std::fmt::*; 87 | struct Point { 88 | x: i32, 89 | y: i32, 90 | } 91 | impl Debug for Point { 92 | fn fmt(&self, f: &mut Formatter) -> Result { 93 | write!(f, "Point {{ x: {}, y: {} }}", self.x, self.y) 94 | } 95 | } 96 | let origin = Point { x: 0, y: 0 }; 97 | println!("The origin is: {:?}", origin); 98 | } 99 | -------------------------------------------------------------------------------- /src/ch02/mod.rs: -------------------------------------------------------------------------------- 1 | //! 第二章:语言精要 2 | //! 3 | 4 | /// # Examples 5 | /// 6 | /// Basic usage: 7 | /// 8 | /// ``` 9 | /// pub fn title(){ 10 | /// println!("第2章:{}", "语言精要"); 11 | /// } 12 | /// title(); 13 | /// ``` 14 | pub fn title(){ 15 | println!("第2章:{}", "语言精要"); 16 | } 17 | 18 | /// # answer 19 | /// 20 | /// Basic usage: 21 | /// 22 | /// ``` 23 | /// // extern crate std; // 声明语句 24 | /// // use std::prelude::v1::*; // 声明语句 25 | /// 26 | /// pub fn answer() -> (){ 27 | /// let a = 40; // 声明语句 28 | /// let b = 2; // 声明语句 29 | /// assert_eq!(sum(a, b), 42); // 宏语句 30 | /// } 31 | /// 32 | /// pub fn sum(a: i32, b: i32) -> i32 { 33 | /// a + b // 表达式 34 | /// } 35 | /// 36 | /// answer(); // 表达式语句 37 | /// ``` 38 | 39 | pub fn answer() -> (){ 40 | let a = 40; 41 | let b = 2; 42 | assert_eq!(sum(a, b), 42); 43 | } 44 | pub fn sum(a: i32, b: i32) -> i32 { 45 | a + b 46 | } 47 | 48 | pub mod binding; 49 | pub mod function; 50 | pub mod control_flow; 51 | pub mod collections; 52 | pub mod primitives; 53 | pub mod enums; 54 | pub mod structs; 55 | pub mod smart_pointer; 56 | pub mod generics_trait; 57 | pub mod errors_handle; 58 | pub mod annotation; 59 | -------------------------------------------------------------------------------- /src/ch02/smart_pointer.rs: -------------------------------------------------------------------------------- 1 | /// # 智能指针:Box 2 | /// 3 | /// Basic usage: 4 | /// 5 | /// ``` 6 | /// fn box_demo(){ 7 | /// #[derive(PartialEq, Debug)] 8 | /// struct Point { 9 | /// x: f64, 10 | /// y: f64, 11 | /// } 12 | /// // 将Point实例装箱(放到堆内存) 13 | /// let box_point = Box::new(Point { x: 0.0, y: 0.0 }); 14 | /// let unboxed_point: Point = *box_point; // 通过解引用操作符取出Point实例 15 | /// assert_eq!(unboxed_point, Point { x: 0.0, y: 0.0 }); 16 | /// } 17 | /// box_demo(); 18 | /// ``` 19 | pub fn box_demo(){ 20 | #[derive(Debug, PartialEq)] 21 | struct Point { 22 | x: f64, 23 | y: f64, 24 | } 25 | let box_point = Box::new(Point { x: 0.0, y: 0.0 }); 26 | let unboxed_point: Point = *box_point; 27 | assert_eq!(unboxed_point, Point { x: 0.0, y: 0.0 }); 28 | } 29 | -------------------------------------------------------------------------------- /src/ch02/structs.rs: -------------------------------------------------------------------------------- 1 | /// # 具名结构体定义 2 | /// 3 | /// Basic usage: 4 | /// 5 | /// ``` 6 | /// #[derive(Debug, PartialEq)] 7 | /// struct People { 8 | /// name: &'static str, 9 | /// gender: u32, 10 | /// } 11 | /// impl People { 12 | /// fn new(name: &'static str, gender: u32) -> Self{ 13 | /// return People{name: name, gender: gender}; 14 | /// } 15 | /// 16 | /// fn name(&self) { 17 | /// println!("name: {:?}", self.name); 18 | /// } 19 | /// 20 | /// fn set_name(&mut self, name: &'static str) { 21 | /// self.name = name; 22 | /// } 23 | /// 24 | /// fn gender(&self){ 25 | /// let gender = if (self.gender == 1) {"boy"} else {"girl"}; 26 | /// println!("gender: {:?}", gender); 27 | /// } 28 | /// } 29 | /// let alex = People::new( "Alex", 1); 30 | /// alex.name(); 31 | /// alex.gender(); 32 | /// assert_eq!(alex, People { name: "Alex", gender: 1 }); 33 | /// 34 | /// let mut alice = People::new("Alice", 0); 35 | /// alice.name(); 36 | /// alice.gender(); 37 | /// assert_eq!(alice, People { name: "Alice", gender: 0 }); 38 | /// alice.set_name("Rose"); 39 | /// alice.name(); 40 | /// assert_eq!(alice, People { name: "Rose", gender: 0 }); 41 | /// ``` 42 | #[derive(Debug, PartialEq)] 43 | pub struct People { 44 | name: &'static str, 45 | gender: u32, 46 | } 47 | impl People { 48 | fn new(name: &'static str, gender: u32) -> Self{ 49 | return People{name: name, gender: gender}; 50 | } 51 | fn name(&self) { 52 | println!("name: {:?}", self.name); 53 | } 54 | fn set_name(&mut self, name: &'static str) { 55 | self.name = name; 56 | } 57 | fn gender(&self){ 58 | let gender = if (self.gender == 1) {"boy"} else {"girl"}; 59 | println!("gender: {:?}", gender); 60 | } 61 | } 62 | 63 | 64 | /// # 元组结构体定义 65 | /// 66 | /// Basic usage: 67 | /// 68 | /// ``` 69 | /// struct Color(i32, i32, i32); 70 | /// let color = Color(0, 1, 2); 71 | /// assert_eq!(color.0, 0); 72 | /// assert_eq!(color.1, 1); 73 | /// assert_eq!(color.2, 2); 74 | /// ``` 75 | pub struct Color(i32, i32, i32); 76 | 77 | 78 | /// # 元组结构体:NewType模式 79 | /// 80 | /// Basic usage: 81 | /// 82 | /// ``` 83 | /// struct Integer(u32); 84 | /// type Int = i32; // 为i32类型创建别名Int 85 | /// let int = Integer(10); 86 | /// assert_eq!(int.0, 10); 87 | /// let int: Int = 10; 88 | /// assert_eq!(int, 10); 89 | /// ``` 90 | pub struct Integer(u32); 91 | 92 | 93 | /// # 单元结构体 94 | /// 95 | /// Basic usage: 96 | /// 97 | /// ``` 98 | /// struct Empty; // 等价于 struct Empty {} 99 | /// struct RangeFull; // 标准库源码中RangeFull就是一个单元结构体 100 | /// assert_eq!((..), std::ops::RangeFull); // RangeFull就是(..),表示全范围 101 | /// let x = Empty; 102 | /// println!("{:p}", &x as *const _); 103 | /// let y = x; 104 | /// println!("{:p}", &y as *const _); 105 | /// let z = Empty; 106 | /// println!("{:p}", &z as *const _); 107 | /// ``` 108 | pub struct Empty; 109 | -------------------------------------------------------------------------------- /src/ch03/abstract_type.rs: -------------------------------------------------------------------------------- 1 | /// # 抽象类型:Box(装箱)抽象类型 之 trait对象 2 | /// 3 | /// Base usage: 4 | /// 5 | /// ``` 6 | /// #[derive(Debug)] 7 | /// struct Foo; 8 | /// trait Bar { 9 | /// fn baz(&self); 10 | /// } 11 | /// impl Bar for Foo { 12 | /// fn baz(&self) { println!("{:?}", self) } 13 | /// } 14 | /// fn static_dispatch(t: &T) where T:Bar { 15 | /// t.baz(); 16 | /// } 17 | /// fn dynamic_dispatch(t: &Bar) { 18 | /// t.baz(); 19 | /// } 20 | /// let foo = Foo; 21 | /// static_dispatch(&foo); 22 | /// dynamic_dispatch(&foo); 23 | /// ``` 24 | pub fn trait_object() { 25 | #[derive(Debug)] 26 | struct Foo; 27 | trait Bar { 28 | fn baz(&self); 29 | } 30 | impl Bar for Foo { 31 | fn baz(&self) { println!("{:?}", self) } 32 | } 33 | fn static_dispatch(t: &T) where T:Bar { 34 | t.baz(); 35 | } 36 | fn dynamic_dispatch(t: &Bar) { 37 | t.baz(); 38 | } 39 | let foo = Foo; 40 | static_dispatch(&foo); 41 | dynamic_dispatch(&foo); 42 | } 43 | 44 | 45 | /// # 抽象类型: impl Trait unbox存在类型 (Rust 2018) 46 | /// 47 | /// Base usage: 重构第二章中trait的示例 48 | /// 49 | /// ``` 50 | /// use std::fmt::Debug; 51 | /// trait Fly { 52 | /// fn fly(&self) -> bool; 53 | /// } 54 | /// #[derive(Debug)] 55 | /// struct Duck; 56 | /// #[derive(Debug)] 57 | /// struct Pig; 58 | /// impl Fly for Duck { 59 | /// fn fly(&self) -> bool { 60 | /// return true; 61 | /// } 62 | /// } 63 | /// impl Fly for Pig { 64 | /// fn fly(&self) -> bool { 65 | /// return false; 66 | /// } 67 | /// } 68 | /// fn fly_static(s: impl Fly+Debug) -> bool { 69 | /// s.fly() 70 | /// } 71 | /// fn can_fly(s: impl Fly+Debug) -> impl Fly { 72 | /// if s.fly(){ 73 | /// println!("{:?} can fly", s); 74 | /// }else{ 75 | /// println!("{:?} can't fly", s); 76 | /// } 77 | /// s 78 | /// } 79 | /// fn dyn_can_fly(s: impl Fly+Debug+'static) -> Box { 80 | /// if s.fly(){ 81 | /// println!("{:?} can fly", s); 82 | /// }else{ 83 | /// println!("{:?} can't fly", s); 84 | /// } 85 | /// Box::new(s) 86 | /// } 87 | /// let pig = Pig; 88 | /// assert_eq!(fly_static(pig), false); // 静态分发 89 | /// let pig = Pig; 90 | /// can_fly(pig); // 静态分发 91 | /// let duck = Duck; 92 | /// assert_eq!(fly_static(duck), true); // 静态分发 93 | /// let duck = Duck; 94 | /// can_fly(duck); // 静态分发 95 | /// let duck = Duck; 96 | /// dyn_can_fly(duck); // 动态分发 97 | /// ``` 98 | /// 99 | /// Base usage: 错误示范 100 | /// 101 | /// ``` 102 | /// use std::ops::Add; 103 | /// // 以下多个参数的情况,虽然同时指定了impl Add类型, 104 | /// // 但是它们并不是同一个类型,因为这是抽象类型。 105 | /// // 所以编译会出错: mismatched types 106 | /// fn sum(a: impl Add, b: impl Add) -> T{ 107 | /// a + b 108 | /// } 109 | /// ``` 110 | /// 111 | /// Base usage: 正确 112 | /// 113 | /// ``` 114 | /// use std::ops::Add; 115 | /// // 只能用于单个参数 116 | /// fn hello(a: impl Add) -> impl Add{ 117 | /// a 118 | /// } 119 | /// ``` 120 | pub fn impl_trait(){ 121 | use std::fmt::Debug; 122 | pub trait Fly { 123 | fn fly(&self) -> bool; 124 | } 125 | #[derive(Debug)] 126 | struct Duck; 127 | #[derive(Debug)] 128 | struct Pig; 129 | impl Fly for Duck { 130 | fn fly(&self) -> bool { 131 | return true; 132 | } 133 | } 134 | impl Fly for Pig { 135 | fn fly(&self) -> bool { 136 | return false; 137 | } 138 | } 139 | fn fly_static(s: impl Fly+Debug) -> bool { 140 | s.fly() 141 | } 142 | fn can_fly(s: impl Fly+Debug) -> impl Fly { 143 | if s.fly(){ 144 | println!("{:?} can fly", s); 145 | }else{ 146 | println!("{:?} can't fly", s); 147 | } 148 | s 149 | } 150 | fn dyn_can_fly(s: impl Fly+Debug+'static) -> Box { 151 | if s.fly(){ 152 | println!("{:?} can fly", s); 153 | }else{ 154 | println!("{:?} can't fly", s); 155 | } 156 | Box::new(s) 157 | } 158 | let pig = Pig; 159 | assert_eq!(fly_static(pig), false); 160 | let duck = Duck; 161 | assert_eq!(fly_static(duck), true); 162 | 163 | let pig = Pig; 164 | can_fly(pig); 165 | let duck = Duck; 166 | can_fly(duck); 167 | 168 | let duck = Duck; 169 | dyn_can_fly(duck); 170 | } 171 | -------------------------------------------------------------------------------- /src/ch03/bottom_type.rs: -------------------------------------------------------------------------------- 1 | /// # 底类型:应用 2 | /// 3 | /// Base usage 4 | /// 5 | /// ``` 6 | /// #![feature(never_type)] 7 | /// fn foo() -> ! { 8 | /// // do something 9 | /// loop { println!("jh"); } 10 | /// } 11 | /// let i = if false { 12 | /// foo(); 13 | /// } else { 14 | /// 100 15 | /// }; 16 | /// assert_eq!(i, 100); 17 | /// ``` 18 | pub fn bottom_type() { 19 | let i = if false { 20 | foo(); 21 | } else { 22 | 100 23 | }; 24 | assert_eq!(i, 100); 25 | } 26 | fn foo() -> ! { 27 | // do something 28 | loop { println!("jh"); } 29 | } 30 | 31 | /// # 底类型:空Enum 32 | /// 33 | /// Base usage:仅仅为了演示,编译并不能通过 34 | /// 35 | /// ``` 36 | /// // 使用enum Void{}就可以避免处理Err的情况,但当前Rust并不支持该用法 37 | /// fn void_enum() { 38 | /// enum Void {} 39 | /// let res: Result = Ok(0); 40 | /// let Ok(num) = res; 41 | /// } 42 | /// ``` 43 | pub fn void_enum() { 44 | // Just for show 45 | 46 | // enum Void {} 47 | // let res: Result = Ok(0); 48 | // let Ok(num) = res; 49 | } 50 | -------------------------------------------------------------------------------- /src/ch03/generics.rs: -------------------------------------------------------------------------------- 1 | /// # 泛型 2 | /// 3 | /// Base usage: 自定义泛型函数 4 | /// 5 | /// ``` 6 | /// fn foo(x: T) -> T { 7 | /// return x; 8 | /// } 9 | /// 10 | /// assert_eq!(foo(1), 1); 11 | /// assert_eq!(foo("hello"), "hello"); 12 | /// ``` 13 | /// 14 | /// Base usage: 自定义泛型结构体 15 | /// 16 | /// ``` 17 | /// struct Point { x: T, y: T } 18 | /// ``` 19 | /// 20 | /// Base usage: `foo`静态分发等价于下面代码 21 | /// 22 | /// ``` 23 | /// fn foo_1(x: i32) -> i32 { 24 | /// return x; 25 | /// } 26 | /// fn foo_2(x: &'static str) -> &'static str { 27 | /// return x; 28 | /// } 29 | /// foo_1(1); 30 | /// foo_2("2"); 31 | /// ``` 32 | pub fn foo(x: T) -> T { 33 | return x; 34 | } 35 | 36 | /// # 泛型: 为泛型结构体实现方法 37 | /// 38 | /// Base usage: 39 | /// 40 | /// ``` 41 | /// fn impl_method(){ 42 | /// #[derive(Debug, PartialEq)] 43 | /// struct Point {x: T, y: T} 44 | /// impl Point { 45 | /// fn new(x: T, y: T) -> Self{ 46 | /// Point{x: x, y: y} 47 | /// } 48 | /// } 49 | /// let point1 = Point::new(1, 2); 50 | /// let point2 = Point::new("1", "2"); 51 | /// assert_eq!(point1, Point{x: 1, y: 2}); 52 | /// assert_eq!(point2, Point{x: "1", y: "2"}); 53 | /// } 54 | /// impl_method(); 55 | /// ``` 56 | pub fn impl_method(){ 57 | #[derive(Debug, PartialEq)] 58 | struct Point {x: T, y: T} 59 | impl Point { 60 | fn new(x: T, y: T) -> Self{ 61 | Point{x: x, y: y} 62 | } 63 | } 64 | let point1 = Point::new(1, 2); 65 | let point2 = Point::new("1", "2"); 66 | assert_eq!(point1, Point{x: 1, y: 2}); 67 | assert_eq!(point2, Point{x: "1", y: "2"}); 68 | } 69 | 70 | /// # 泛型: 返回值自动推导 71 | /// 72 | /// Base usage: 73 | /// 74 | /// ``` 75 | /// fn infer_generics(){ 76 | /// #[derive(Debug, PartialEq)] 77 | /// struct Foo(i32); 78 | /// #[derive(Debug, PartialEq)] 79 | /// struct Bar(i32, i32); 80 | /// trait Inst { 81 | /// fn new(i: i32) -> Self; 82 | /// } 83 | /// impl Inst for Foo { 84 | /// fn new(i: i32) -> Foo { 85 | /// Foo(i) 86 | /// } 87 | /// } 88 | /// impl Inst for Bar { 89 | /// fn new(i: i32) -> Bar { 90 | /// Bar(i, i + 10) 91 | /// } 92 | /// } 93 | /// fn foobar(i: i32) -> T { 94 | /// T::new(i) 95 | /// } 96 | /// let f: Foo = foobar(10); 97 | /// assert_eq!(f, Foo(10)); 98 | /// let b: Bar = foobar(20); 99 | /// assert_eq!(b, Bar(20, 30)); 100 | /// } 101 | /// infer_generics(); 102 | /// ``` 103 | pub fn infer_generics(){ 104 | #[derive(Debug, PartialEq)] 105 | struct Foo(i32); 106 | #[derive(Debug, PartialEq)] 107 | struct Bar(i32, i32); 108 | trait Inst { 109 | fn new(i: i32) -> Self; 110 | } 111 | impl Inst for Foo { 112 | fn new(i: i32) -> Foo { 113 | Foo(i) 114 | } 115 | } 116 | impl Inst for Bar { 117 | fn new(i: i32) -> Bar { 118 | Bar(i, i + 10) 119 | } 120 | } 121 | fn foobar(i: i32) -> T { 122 | T::new(i) 123 | } 124 | let f: Foo = foobar(10); 125 | assert_eq!(f, Foo(10)); 126 | let b: Bar = foobar(20); 127 | assert_eq!(b, Bar(20, 30)); 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/ch03/mod.rs: -------------------------------------------------------------------------------- 1 | //! 第三章:类型系统 2 | //! 3 | 4 | /// # Examples 5 | /// 6 | /// Basic usage: 7 | /// 8 | /// ``` 9 | /// pub fn title(){ 10 | /// println!("第3章:{}", "类型系统"); 11 | /// } 12 | /// title(); 13 | /// ``` 14 | pub fn title(){ 15 | println!("第3章:{}", "类型系统"); 16 | } 17 | 18 | pub mod type_size; 19 | pub mod zero_size; 20 | pub mod bottom_type; 21 | pub mod type_infer; 22 | pub mod generics; 23 | pub mod traits; 24 | pub mod abstract_type; 25 | pub mod tag_trait; 26 | pub mod type_cast; 27 | pub mod trait_limit; 28 | -------------------------------------------------------------------------------- /src/ch03/tag_trait.rs: -------------------------------------------------------------------------------- 1 | /// # 用作标签的trait:Copy 2 | /// 3 | /// 实现Copy必须也实现Clone 4 | /// 5 | /// Base usage: 6 | /// 7 | /// ``` 8 | /// struct MyStruct; 9 | /// impl Copy for MyStruct { } 10 | /// impl Clone for MyStruct { 11 | /// fn clone(&self) -> MyStruct { 12 | /// *self 13 | /// } 14 | /// } 15 | /// ``` 16 | /// 17 | /// Base usage: 可以用derive属性自动生成Copy 18 | /// 19 | /// ``` 20 | /// #[derive(Copy, Clone)] 21 | /// struct MyStruct; 22 | /// ``` 23 | pub fn impl_clone(){ 24 | struct MyStruct; 25 | impl Copy for MyStruct { } 26 | impl Clone for MyStruct { 27 | fn clone(&self) -> MyStruct { 28 | *self 29 | } 30 | } 31 | } 32 | 33 | /// # 用作标签的trait:Copy 34 | /// 35 | /// 在Rust中一共有五种主要的标签trait: 36 | /// 37 | /// - Sized。用来标识编译期可确定大小的类型。 38 | /// - Unsize。目前该Trait为实验特性,用于标识动态大小类型(DST)。 39 | /// - Copy。用来标识可以按位复制其值的类型。 40 | /// - Send。用来标识可以跨线程安全通信的类型。 41 | /// - Sync。用来标识可以在线程间安全共享引用的类型。 42 | /// 43 | /// Base usage: 检测是否实现Copy trait的函数 44 | /// 45 | /// ``` 46 | /// fn test_copy(i: T) { 47 | /// println!("hhh"); 48 | /// } 49 | /// let a = "String".to_string(); 50 | /// test_copy(a); 51 | /// ``` 52 | pub fn test_copy_trait(){ 53 | fn test_copy(i: T) { 54 | println!("hhh"); 55 | } 56 | let a = "String"; 57 | test_copy(a); 58 | } 59 | 60 | /// # 用作标签的trait:Sync / Send 61 | /// 62 | /// Base usage: error 63 | /// 利用所有权机制化解了一次并发危机 64 | /// ``` 65 | /// use std::thread; 66 | /// let mut x = vec![1, 2, 3, 4]; 67 | /// thread::spawn(|| { // Error: may outlive borrowed value `x` 68 | /// x.push(1); // 子线程修改x 69 | /// }); 70 | /// x.push(2); // 父线程修改x 71 | /// ``` 72 | /// 73 | /// Base usage: right 74 | /// 使用move关键字, 75 | /// ``` 76 | /// use std::thread; 77 | /// let mut x = vec![1, 2, 3, 4]; 78 | /// thread::spawn(move || { // x实现了Sync和Send 79 | /// x.push(1); 80 | /// }); 81 | /// //x.push(2); // 父线程不允许修改x 82 | /// ``` 83 | /// 84 | /// Base usage: 未实现Sync和Send的类型示范 85 | /// ``` 86 | /// use std::thread; 87 | /// use std::rc::Rc; 88 | /// 89 | /// let x = Rc::new(vec![1, 2, 3, 4]); 90 | /// thread::spawn( move || { // Error: std::marker::Send is not satisfied 91 | /// x[1]; 92 | /// }); 93 | /// ``` 94 | pub fn sync_send_trait(){ 95 | use std::thread; 96 | let mut x = vec![1, 2, 3, 4]; 97 | thread::spawn(move || x.push(1)); 98 | } 99 | -------------------------------------------------------------------------------- /src/ch03/trait_limit.rs: -------------------------------------------------------------------------------- 1 | /// # trait局限 2 | /// 3 | /// Base usage: 作为父crate在考虑设计trait时,不得不考虑要不要给全体的T或&'a T实现trait 4 | /// 才能不影响到子crate 5 | /// ``` 6 | /// impl Bar for T { } 7 | /// impl<'a,T:Bar> Bar for &'a T { } 8 | /// ``` 9 | /// 10 | /// Base usage: 11 | /// 12 | /// ``` 13 | /// use std::ops::Add; 14 | /// #[derive(PartialEq)] 15 | /// struct Int(i32); 16 | /// impl Add for Int { 17 | /// type Output = i32; 18 | /// fn add(self, other: i32) -> Self::Output { 19 | /// (self.0) + other 20 | /// } 21 | /// } 22 | /// // impl Add for Option { 23 | /// // // TODO 24 | /// // } 25 | /// impl Add for Box { 26 | /// type Output = i32; 27 | /// fn add(self, other: i32) -> Self::Output { 28 | /// (self.0) + other 29 | /// } 30 | /// } 31 | /// 32 | /// assert_eq!(Int(3) + 3, 6); 33 | /// assert_eq!(Box::new(Int(3)) + 3, 6); 34 | /// ``` 35 | pub fn trait_limit(){ 36 | use std::ops::Add; 37 | #[derive(PartialEq)] 38 | struct Int(i32); 39 | impl Add for Int { 40 | type Output = i32; 41 | fn add(self, other: i32) -> Self::Output { 42 | (self.0) + other 43 | } 44 | } 45 | // impl Add for Option { 46 | // // TODO 47 | // } 48 | impl Add for Box { 49 | type Output = i32; 50 | fn add(self, other: i32) -> Self::Output { 51 | (self.0) + other 52 | } 53 | } 54 | assert_eq!(Int(3) + 3, 6); 55 | assert_eq!(Box::new(Int(3)) + 3, 6); 56 | 57 | } 58 | 59 | 60 | /// # trait: 特化(specialization) 61 | /// 62 | /// 重叠规则:不能为重叠的类型实现同一个trait 63 | /// 以下代码会编译失败。这种实现方式也被称为覆盖式实现(blanket impl) 64 | /// ``` 65 | /// impl AnyTrait for T 66 | /// impl AnyTrait for T where T: Copy 67 | /// impl AnyTrait for String 68 | /// ``` 69 | /// 70 | /// 第一个问题:性能问题 71 | /// 72 | /// 以下代码为所有类型T实现了AddAssign,也就是 += 操作, 73 | /// 这样实现虽然好,但是会带来性能问题,因为强制使用了clone方法,但实际上有的类型并不需要clone。 74 | /// 而因为有重叠规则的限制,并不能为某些不需要clone的具体类型重新实现add_assign方法。 75 | /// 所以,在标准库中,就基本上为每个具体的类型都各自实现了一遍AddAssign。 76 | /// 77 | /// 第二个问题:代码重用 78 | /// 79 | /// 如果没有重叠规则,则可以默认使用上面对泛型T的实现, 80 | /// 然后对不需要clone的类型重新实现AddAssign,那么就完全没必要为每个具体类型都实现一遍add_assign方法, 81 | /// 可以省掉很多重复代码 82 | /// 83 | /// ``` 84 | /// impl + Clone> AddAssign for T { 85 | /// fn add_assign(&mut self, rhs: R) { 86 | /// let tmp = self.clone() + rhs; 87 | /// *self = tmp; 88 | /// } 89 | /// } 90 | /// ``` 91 | /// 92 | /// Basic usage: 使用特化之trait默认实现 93 | /// 94 | /// ``` 95 | /// #![feature(specialization)] 96 | /// struct Diver { 97 | /// inner: T, 98 | /// } 99 | /// trait Swimmer { 100 | /// fn swim(&self) { 101 | /// println!("swimming") 102 | /// } 103 | /// } 104 | /// impl Swimmer for Diver {} 105 | /// 106 | /// impl Swimmer for Diver<&'static str> { 107 | /// fn swim(&self) { 108 | /// println!("drowning, help!") 109 | /// } 110 | /// } 111 | /// 112 | /// let x = Diver::<&'static str> { inner: "Bob" }; 113 | /// x.swim(); 114 | /// let y = Diver:: { inner: String::from("Alice") }; 115 | /// y.swim(); 116 | /// ``` 117 | // 118 | /// Basic usage: 使用特化之default关键字 119 | /// 120 | /// ``` 121 | /// #![feature(specialization)] 122 | /// struct Diver { 123 | /// inner: T, 124 | /// } 125 | /// trait Swimmer { 126 | /// fn swim(&self); 127 | /// } 128 | /// impl Swimmer for Diver { 129 | /// default fn swim(&self) { 130 | /// println!("swimming") 131 | /// } 132 | /// } 133 | /// 134 | /// impl Swimmer for Diver<&'static str> { 135 | /// fn swim(&self) { 136 | /// println!("drowning, help!") 137 | /// } 138 | /// } 139 | /// 140 | /// let x = Diver::<&'static str> { inner: "Bob" }; 141 | /// x.swim(); 142 | /// let y = Diver:: { inner: String::from("Alice") }; 143 | /// y.swim(); 144 | /// ``` 145 | pub fn trait_special(){ 146 | struct Diver { 147 | inner: T, 148 | } 149 | trait Swimmer { 150 | fn swim(&self) { 151 | println!("swimming") 152 | } 153 | } 154 | impl Swimmer for Diver {} 155 | 156 | impl Swimmer for Diver<&'static str> { 157 | fn swim(&self) { 158 | println!("drowning, help!") 159 | } 160 | } 161 | 162 | let x = Diver::<&'static str> { inner: "Bob" }; 163 | x.swim() 164 | } 165 | 166 | /// # trait局限: GAT(Generic Associated Type) 或 ATC(Associated type constructor) 167 | /// 168 | /// Rust标准库中的迭代器API不允许生成从迭代器本身借用的元素。 169 | /// 比如std::io::Lines,其实现迭代器只能读一行数据分配一个新的String,而不能重用内部缓存区。 170 | /// 而流式迭代器可以允许通过引用迭代,而不是值,这样就可以实现重用。 171 | /// 想要支持这种StreamingIterator,就必须实现一种更高级别的类型多态性, 172 | /// 所以GAT 将会把Rust类型系统扩展到支持特点形式的高级多态性,称为泛型关联类型,也叫做关联类型构造函数 173 | /// 174 | /// 不过,当前此功能还未实现, 175 | /// 相关[RFC1598](https://github.com/rust-lang/rfcs/blob/master/text/1598-generic_associated_types.md) 176 | /// 177 | /// Base usage: 178 | /// 179 | /// ``` 180 | /// trait StreamingIterator { 181 | /// type Item<'a>; 182 | /// fn next<'a>(&'a mut self) -> Option>; 183 | /// } 184 | /// ``` 185 | pub fn gat(){ 186 | unimplemented!(); 187 | } 188 | -------------------------------------------------------------------------------- /src/ch03/type_cast.rs: -------------------------------------------------------------------------------- 1 | /// # 类型转换:自动解引用(For SmartPointer) 2 | /// 3 | /// Base usage: `Vec`实现了`Deref` 4 | /// 5 | /// ``` 6 | /// fn foo(s: &[i32]){ 7 | /// println!("{:?}", s[0]); 8 | /// } 9 | /// 10 | /// let v = vec![1,2,3]; 11 | /// foo(&v) 12 | /// ``` 13 | /// 14 | /// Base usage: `String`实现了`Deref` 15 | /// 16 | /// ``` 17 | /// let a = "hello".to_string(); 18 | /// let b = " world".to_string(); 19 | /// let c = a + &b; 20 | /// println!("{:?}", c); // "hello world" 21 | /// ``` 22 | // 23 | /// Base usage: `Rc`实现了`Deref>` 24 | /// 25 | /// ``` 26 | /// use std::rc::Rc; 27 | /// let x = Rc::new("hello"); 28 | /// println!("{:?}", x.chars()); 29 | /// ``` 30 | pub fn auto_deref(){ 31 | fn foo(s: &[i32]){ 32 | println!("{:?}", s[0]); 33 | } 34 | 35 | let v = vec![1,2,3]; 36 | foo(&v) 37 | } 38 | 39 | /// # 类型转换:手动解引用(For SmartPointer) 40 | /// 41 | /// Base usage: `Rc` 和 `&str` 都实现了clone 42 | /// 43 | /// ``` 44 | /// use std::rc::Rc; 45 | /// 46 | /// let x = Rc::new("hello"); 47 | /// let y = x.clone(); // Rc<&str> 48 | /// let z = (*x).clone(); // &str 49 | /// ``` 50 | /// 51 | /// Base usage: match匹配里需要手动解引用 52 | /// 53 | /// 将match &x改为以下5种形式任意一种即可: 54 | /// - match x.deref(),直接调用deref方法,需要use std::ops::Deref。 55 | /// - match x.as_ref(),String类型提供了as_ref方法来返回一个&str类型,该方法定义于AsRef trait中。 56 | /// - match x.borrow(),方法borrow定义于Borrow trait中,行为和AsRef类型。需要use std::borrow::Borrow。 57 | /// - match &*x,使用“解引用”操作符,将String转换为str,然后再用“引用”操作符转为&str。 58 | /// - match &x[..],这是因为String类型的index操作可以返回&str类型。 59 | /// 60 | /// ``` 61 | /// let x = "hello".to_string(); 62 | /// match &x { 63 | /// "hello" => {println!("hello")}, 64 | /// _ => {} 65 | /// } 66 | /// ``` 67 | pub fn manual_deref(){ 68 | use std::rc::Rc; 69 | 70 | let x = Rc::new("hello"); 71 | let y = x.clone(); // Rc<&str> 72 | let z = (*x).clone(); // &str 73 | } 74 | 75 | /// # 类型转换:as 操作符 76 | /// 77 | /// Base usage: 无歧义完全限定语法(Fully Qualified Syntax for Disambiguation) 78 | /// 曾用名: 通用函数调用语法(UFCS) 79 | /// ``` 80 | /// struct S(i32); 81 | /// trait A { 82 | /// fn test(&self, i: i32); 83 | /// } 84 | /// trait B { 85 | /// fn test(&self, i: i32); 86 | /// } 87 | /// impl A for S { 88 | /// fn test(&self, i: i32) { 89 | /// println!("From A: {:?}", i); 90 | /// } 91 | /// } 92 | /// impl B for S { 93 | /// fn test(&self, i: i32) { 94 | /// println!("From B: {:?}", i+1); 95 | /// } 96 | /// } 97 | /// 98 | /// let s = S(1); 99 | /// A::test(&s, 1); 100 | /// B::test(&s, 1); 101 | /// ::test(&s, 1); 102 | /// ::test(&s, 1); 103 | /// ``` 104 | /// 105 | /// Base usage: 父类型子类型相互转换 106 | /// ``` 107 | /// let a: &'static str = "hello"; // &'static str 108 | /// let b: &str = a as &str; // &str 109 | /// let c: &'static str = b as &'static str; // &'static str 110 | /// ``` 111 | pub fn fqsfd(){ 112 | struct S(i32); 113 | trait A { 114 | fn test(&self, i: i32); 115 | } 116 | trait B { 117 | fn test(&self, i: i32); 118 | } 119 | impl A for S { 120 | fn test(&self, i: i32) { 121 | println!("From A: {:?}", i); 122 | } 123 | } 124 | impl B for S { 125 | fn test(&self, i: i32) { 126 | println!("From B: {:?}", i+1); 127 | } 128 | } 129 | 130 | let s = S(1); 131 | A::test(&s, 1); 132 | B::test(&s, 1); 133 | ::test(&s, 1); 134 | ::test(&s, 1); 135 | } 136 | 137 | /// # 类型转换:From和Into 138 | /// 139 | /// Base usage: String实现了From 140 | /// 141 | /// ``` 142 | /// let string = "hello".to_string(); 143 | /// let other_string = String::from("hello"); 144 | /// assert_eq!(string, other_string); 145 | /// ``` 146 | /// 147 | /// Base usage: 使用into简化代码 148 | /// 149 | /// ``` 150 | /// #[derive(Debug)] 151 | /// struct Person{ name: String } 152 | /// impl Person { 153 | /// fn new>(name: T) -> Person { 154 | /// Person {name: name.into()} 155 | /// } 156 | /// } 157 | /// let person = Person::new("Alex"); 158 | /// let person = Person::new("Alex".to_string()); 159 | /// println!("{:?}", person); 160 | /// ``` 161 | pub fn from_into(){ 162 | let string = "hello".to_string(); 163 | let other_string = String::from("hello"); 164 | assert_eq!(string, other_string); 165 | } 166 | -------------------------------------------------------------------------------- /src/ch03/type_infer.rs: -------------------------------------------------------------------------------- 1 | /// # 类型推导 2 | /// 3 | /// Base usage: 正常推导 4 | /// 5 | /// ``` 6 | /// fn sum(a: u32, b: i32) -> u32 { 7 | /// a + (b as u32) 8 | /// } 9 | /// fn infer_demo() { 10 | /// let a = 1; 11 | /// let b = 2; 12 | /// assert_eq!(sum(a, b), 3); // a和b的类型会自动推断为i32 13 | /// let elem = 5u8; 14 | /// let mut vec = Vec::new(); 15 | /// vec.push(elem); // vec 类型会自动推断为 u8 16 | /// assert_eq!(vec, [5]); 17 | /// } 18 | /// infer_demo(); 19 | /// ``` 20 | /// 21 | /// Base usage: 无法推导的情况 22 | /// 23 | /// ``` 24 | /// let x = "1"; 25 | /// println!("{:?}", x.parse().unwrap()); 26 | /// ``` 27 | /// 28 | /// Base usage: 解决无法推导的情况 29 | /// 30 | /// ``` 31 | /// let x = "1"; 32 | /// println!("{:?}", x.parse::().unwrap()); 33 | /// ``` 34 | /// 35 | /// Base usage: 另一种类型无法推导的情况 36 | /// 37 | /// ``` 38 | /// let a = 0; 39 | /// let a_pos = a.is_positive(); // error`[E0599]`: no method named `is_positive` found for type `{integer}` in the current scope 40 | /// ``` 41 | pub fn infer_demo() { 42 | let a = 1; 43 | let b = 2; 44 | assert_eq!(sum(a, b), 3); 45 | let elem = 5u8; 46 | let mut vec = Vec::new(); 47 | vec.push(elem); 48 | assert_eq!(vec, [5]); 49 | } 50 | fn sum(a: u32, b: i32) -> u32 { 51 | a + (b as u32) 52 | } 53 | -------------------------------------------------------------------------------- /src/ch03/type_size.rs: -------------------------------------------------------------------------------- 1 | /// # 动态大小类型:str 2 | /// ### 探索&str的组成 3 | /// 4 | /// Basic usage: 5 | /// 6 | /// ``` 7 | /// fn str_compose(){ 8 | /// let str = "Hello Rust"; 9 | /// let ptr = str.as_ptr(); 10 | /// let len = str.len(); 11 | /// println!("{:p}", ptr); // 0x555db4b96c00 12 | /// println!("{:?}", len); // 10 13 | /// } 14 | /// str_compose(); 15 | /// ``` 16 | pub fn str_compose(){ 17 | let str = "Hello Rust"; 18 | let ptr = str.as_ptr(); 19 | let len = str.len(); 20 | println!("{:p}", ptr); // 0x555db4b96c00 21 | println!("{:?}", len); // 10 22 | } 23 | 24 | /// # 动态大小类型:`[T]` 25 | /// ### 探索数组 26 | /// 27 | /// Error usage: 28 | /// 29 | /// ``` 30 | /// // Error: `[u32]` does not have a constant size known at compile-time 31 | /// fn reset(mut arr: [u32]) { 32 | /// arr[0] = 5; 33 | /// arr[1] = 4; 34 | /// arr[2] = 3; 35 | /// arr[3] = 2; 36 | /// arr[4] = 1; 37 | /// println!("reset arr {:?}", arr); 38 | /// } 39 | /// let arr: [u32] = [1, 2, 3, 4, 5]; 40 | /// reset(arr); 41 | /// println!("origin arr {:?}", arr); 42 | /// ``` 43 | /// 44 | /// Right usage 1: 指定固定长度 45 | /// 46 | /// ``` 47 | /// fn reset(mut arr: [u32; 5]) { 48 | /// arr[0] = 5; 49 | /// arr[1] = 4; 50 | /// arr[2] = 3; 51 | /// arr[3] = 2; 52 | /// arr[4] = 1; 53 | /// println!("reset arr {:?}", arr); 54 | /// } 55 | /// let arr: [u32; 5] = [1, 2, 3, 4, 5]; 56 | /// reset(arr); 57 | /// println!("origin arr {:?}", arr); 58 | /// ``` 59 | /// 60 | /// Right usage 2: 使用胖指针 61 | /// 62 | /// ``` 63 | /// fn reset(arr: &mut[u32]) { 64 | /// arr[0] = 5; 65 | /// arr[1] = 4; 66 | /// arr[2] = 3; 67 | /// arr[3] = 2; 68 | /// arr[4] = 1; 69 | /// println!("reset arr {:?}", arr); 70 | /// } 71 | /// let mut arr = [1, 2, 3, 4, 5]; 72 | /// println!("reset before : origin array {:?}", arr); 73 | /// { 74 | /// let mut_arr: &mut[u32] = &mut arr; 75 | /// reset(mut_arr); 76 | /// } 77 | /// println!("reset after : origin array {:?}", arr); 78 | /// ``` 79 | pub fn reset(mut arr: [u32; 5]) { 80 | arr[0] = 5; 81 | arr[1] = 4; 82 | arr[2] = 3; 83 | arr[3] = 2; 84 | arr[4] = 1; 85 | println!("reset arr {:?}", arr); 86 | } 87 | 88 | 89 | /// # 动态大小类型:比较`&[u32; 5]`和`&mut [u32]`的空间占用 90 | /// 91 | /// Base usage: 92 | /// 93 | /// ``` 94 | /// fn compare_size(){ 95 | /// assert_eq!(std::mem::size_of::<&[u32; 5]>(), 8); 96 | /// assert_eq!(std::mem::size_of::<&mut [u32]>(), 16); 97 | /// } 98 | /// compare_size(); 99 | /// ``` 100 | pub fn compare_size(){ 101 | use std::mem::size_of; 102 | assert_eq!(size_of::<&[u32; 5]>(), 8); 103 | assert_eq!(size_of::<&mut [u32]>(), 16); 104 | } 105 | -------------------------------------------------------------------------------- /src/ch03/zero_size.rs: -------------------------------------------------------------------------------- 1 | /// # 零大小类型: 2 | /// 3 | /// Base usage: 4 | /// 5 | /// ``` 6 | /// fn zero_size(){ 7 | /// enum Void {} 8 | /// struct Foo; 9 | /// struct Baz { 10 | /// foo: Foo, 11 | /// qux: (), 12 | /// baz: [u8; 0], 13 | /// } 14 | /// assert_eq!(std::mem::size_of::<()>(), 0); 15 | /// assert_eq!(std::mem::size_of::(), 0); 16 | /// assert_eq!(std::mem::size_of::(), 0); 17 | /// assert_eq!(std::mem::size_of::(), 0); 18 | /// assert_eq!(std::mem::size_of::<[(); 10]>(), 0); 19 | /// } 20 | /// zero_size(); 21 | /// ``` 22 | pub fn zero_size(){ 23 | use std::mem::size_of; 24 | enum Void {} 25 | struct Foo; 26 | struct Baz { 27 | foo: Foo, 28 | qux: (), 29 | baz: [u8; 0], 30 | } 31 | assert_eq!(size_of::<()>(), 0); 32 | assert_eq!(size_of::(), 0); 33 | assert_eq!(size_of::(), 0); 34 | assert_eq!(size_of::(), 0); 35 | assert_eq!(size_of::<[(); 10]>(), 0); 36 | } 37 | 38 | /// # 零大小类型:应用 39 | /// 40 | /// Base usage: 利用单元类型查看值的类型 41 | /// 42 | /// ``` 43 | /// let v: () = vec![(); 10]; // Error: expected (), found struct `std::vec::Vec` 44 | /// ``` 45 | /// 46 | /// Base usage: 零大小循环 47 | /// 48 | /// ``` 49 | /// fn zero_size_loop(){ 50 | /// let v: Vec<()> = vec![(); 10]; 51 | /// for i in v { 52 | /// println!("{:?}", i); 53 | /// } 54 | /// } 55 | /// zero_size_loop(); 56 | /// ``` 57 | pub fn zero_size_loop(){ 58 | let v: Vec<()> = vec![(); 10]; 59 | for i in v { 60 | println!("{:?}", i); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/ch04/general_concepts.rs: -------------------------------------------------------------------------------- 1 | /// # 栈: 2 | /// 3 | /// Base usage: 简单函数调用栈帧展示 4 | /// 参考图4-5 5 | /// ``` 6 | /// fn foo(x: u32) { // ------+ 7 | /// let y = x; // | foo 函数栈帧 8 | /// let z = 100; // | 其实就是foo函数作用域 9 | /// } // ------+ 10 | /// fn main(){ // ------+ 11 | /// let x = 42; // | main函数栈帧 12 | /// foo(x); // | 13 | /// } // ------+ 14 | /// ``` 15 | pub fn simple_stack_frame(){ 16 | 17 | fn foo(x: u32) { 18 | let y = x; 19 | let z = 100; 20 | } 21 | fn main(){ 22 | let x = 42; 23 | foo(x); 24 | } 25 | 26 | } 27 | 28 | 29 | /// # 内存对齐: 30 | /// 31 | /// Base usage: 结构体内存对齐 32 | /// ``` 33 | /// struct A { 34 | /// a: u8, 35 | /// b: u32, 36 | /// c: u16, 37 | /// } 38 | /// fn main() { 39 | /// println!("{:?}", std::mem::size_of::()); // 8 40 | /// } // ------+ 41 | /// ``` 42 | /// 43 | /// Base usage: Union内存对齐 44 | /// ``` 45 | /// union U { 46 | /// f1: u32, 47 | /// f2: f32, 48 | /// f3: f64 49 | /// } 50 | /// fn main() { 51 | /// println!("{:?}", std::mem::size_of::()); // 8 52 | /// } 53 | /// ``` 54 | pub fn memory_align(){ 55 | use std::mem; 56 | struct A { 57 | a: u8, 58 | b: u32, 59 | c: u16, 60 | } 61 | fn main() { 62 | println!("{:?}", mem::size_of::()); // 8 63 | } 64 | 65 | } 66 | 67 | /// # 复合结构内存布局 68 | /// 69 | /// Base usage: 结构体内存对齐 70 | /// ``` 71 | /// struct A { 72 | /// a: u32, 73 | /// b: Box, 74 | /// } 75 | /// struct B(i32, f64, char); 76 | /// struct N; 77 | /// enum E { 78 | /// H(u32), 79 | /// M(Box) 80 | /// } 81 | /// union U { 82 | /// u: u32, 83 | /// v: u64 84 | /// } 85 | /// fn main(){ 86 | /// println!("Box: {:?}", std::mem::size_of::>()); 87 | /// println!("A: {:?}", std::mem::size_of::()); 88 | /// println!("B: {:?}", std::mem::size_of::()); 89 | /// println!("N: {:?}", std::mem::size_of::()); 90 | /// println!("E: {:?}", std::mem::size_of::()); 91 | /// println!("U: {:?}", std::mem::size_of::()); 92 | /// } 93 | /// ``` 94 | pub fn memory_layout(){ 95 | use std::mem; 96 | struct A { 97 | a: u32, 98 | b: Box, 99 | } 100 | struct B(i32, f64, char); 101 | struct N; 102 | enum E { 103 | H(u32), 104 | M(Box) 105 | } 106 | union U { 107 | u: u32, 108 | v: u64 109 | } 110 | fn main(){ 111 | println!("Box: {:?}", mem::size_of::>()); 112 | println!("A: {:?}", mem::size_of::()); 113 | println!("B: {:?}", mem::size_of::()); 114 | println!("N: {:?}", mem::size_of::()); 115 | println!("E: {:?}", mem::size_of::()); 116 | println!("U: {:?}", mem::size_of::()); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/ch04/memory_leak.rs: -------------------------------------------------------------------------------- 1 | /// # 制造内存泄漏 2 | /// 3 | /// Base usage: 内存泄漏不属于内存安全范围 4 | /// 内存泄漏是可以通过相互引用精心构造出来的 5 | /// ``` 6 | /// fn main() { 7 | /// use std::rc::Rc; 8 | /// use std::cell::RefCell; 9 | /// type NodePtr = Option>>>; 10 | /// struct Node { 11 | /// data: T, 12 | /// next: NodePtr, 13 | /// } 14 | /// impl Drop for Node { 15 | /// fn drop(&mut self) { 16 | /// println!("Dropping!"); 17 | /// } 18 | /// } 19 | /// fn main() { 20 | /// let first = Rc::new(RefCell::new(Node { 21 | /// data: 1, 22 | /// next: None, 23 | /// })); 24 | /// let second = Rc::new(RefCell::new(Node { 25 | /// data: 2, 26 | /// next: Some(first.clone()), 27 | /// })); 28 | /// first.borrow_mut().next = Some(second.clone()); 29 | /// second.borrow_mut().next = Some(first.clone()); 30 | /// } 31 | /// } 32 | /// ``` 33 | fn memory_leak(){ 34 | use std::rc::Rc; 35 | use std::cell::RefCell; 36 | type NodePtr = Option>>>; 37 | struct Node { 38 | data: T, 39 | next: NodePtr, 40 | } 41 | impl Drop for Node { 42 | fn drop(&mut self) { 43 | println!("Dropping!"); 44 | } 45 | } 46 | fn main() { 47 | let first = Rc::new(RefCell::new(Node { 48 | data: 1, 49 | next: None, 50 | })); 51 | let second = Rc::new(RefCell::new(Node { 52 | data: 2, 53 | next: Some(first.clone()), 54 | })); 55 | first.borrow_mut().next = Some(second.clone()); 56 | second.borrow_mut().next = Some(first.clone()); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/ch04/mod.rs: -------------------------------------------------------------------------------- 1 | //! 第四章:内存管理 2 | //! 3 | 4 | /// # Examples 5 | /// 6 | /// Basic usage: 7 | /// 8 | /// ``` 9 | /// pub fn title(){ 10 | /// println!("第4章:{}", "内存管理"); 11 | /// } 12 | /// title(); 13 | /// ``` 14 | pub fn title(){ 15 | println!("第4章:{}", "内存管理"); 16 | } 17 | 18 | pub mod general_concepts; 19 | pub mod resource_management; 20 | pub mod raii; 21 | -------------------------------------------------------------------------------- /src/ch04/raii.rs: -------------------------------------------------------------------------------- 1 | /// # 智能指针: 2 | /// 3 | /// Base usage: 智能指针示意 4 | /// ``` 5 | /// fn main() { 6 | /// let s = String::from("hello"); 7 | /// // let deref_s : str = *s; 8 | /// let v = vec![1,2,3]; 9 | /// // let deref_v: [u32] = *v; 10 | /// } 11 | /// ``` 12 | pub fn smart_pointer(){ 13 | fn main() { 14 | let s = String::from("hello"); 15 | // let deref_s : str = *s; 16 | let v = vec![1,2,3]; 17 | // let deref_v: [u32] = *v; 18 | } 19 | 20 | } 21 | 22 | /// # RAII: 确定性析构 23 | /// 24 | /// Base usage: 实现Drop 25 | /// ``` 26 | /// use std::ops::Drop; 27 | /// #[derive(Debug)] 28 | /// struct S(i32); 29 | /// impl Drop for S { 30 | /// fn drop(&mut self) { 31 | /// println!("drop {}", self.0); 32 | /// } 33 | /// } 34 | /// fn main() { 35 | /// let x = S(1); 36 | /// println!("crate x: {:?}", x); 37 | /// { 38 | /// let y = S(2); 39 | /// println!("crate y: {:?}", y); 40 | /// println!("exit inner scope"); 41 | /// } 42 | /// println!("exit main"); 43 | /// } 44 | /// ``` 45 | /// 46 | /// Base usage: 配合Valgrind工具来检查是否会内存泄漏 47 | /// 看看Box是否会自动释放 48 | /// ``` 49 | /// fn create_box() { 50 | /// let box3 = Box::new(3); 51 | /// } 52 | /// fn main() { 53 | /// let box1 = Box::new(1); 54 | /// { 55 | /// let box2 = Box::new(2); 56 | /// } 57 | /// for _ in 0..1_000 { 58 | /// create_box(); 59 | /// } 60 | /// } 61 | /// ``` 62 | /// 63 | /// Base usage: 使用花括号块主动析构 64 | /// ``` 65 | /// fn main() { 66 | /// let mut v = vec![1, 2, 3]; 67 | /// { 68 | /// v 69 | /// }; 70 | /// // v.push(4); 71 | /// } 72 | /// ``` 73 | /// 74 | /// Base usage: 变量遮蔽不等于drop 75 | /// ``` 76 | /// use std::ops::Drop; 77 | /// #[derive(Debug)] 78 | /// struct S(i32); 79 | /// impl Drop for S { 80 | /// fn drop(&mut self) { 81 | /// println!("drop for {}", self.0); 82 | /// } 83 | /// } 84 | /// fn main() { 85 | /// let x = S(1); 86 | /// println!("create x: {:?}", x); 87 | /// let x = S(2); 88 | /// println!("create shadowing x: {:?}", x); 89 | /// } 90 | /// ``` 91 | pub fn drop_demo(){ 92 | use std::ops::Drop; 93 | #[derive(Debug)] 94 | struct S(i32); 95 | impl Drop for S { 96 | fn drop(&mut self) { 97 | println!("drop {}", self.0); 98 | } 99 | } 100 | fn main() { 101 | let x = S(1); 102 | println!("crate x: {:?}", x); 103 | { 104 | let y = S(2); 105 | println!("crate y: {:?}", y); 106 | println!("exit inner scope"); 107 | } 108 | println!("exit main"); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/ch04/resource_management.rs: -------------------------------------------------------------------------------- 1 | /// # 资源管理: 2 | /// 3 | /// Base usage: 变量与函数 4 | /// 变量默认存储在栈中 5 | /// ``` 6 | /// fn main() { 7 | /// let x: i32; // Rust会检查未初始化的变量,并报错 8 | /// println!("{}", x); 9 | /// } 10 | /// ``` 11 | /// 12 | /// Base usage: if 分支检查 13 | /// ``` 14 | /// fn main() { 15 | /// let x: i32; 16 | /// if true { 17 | /// x = 1; 18 | /// } else { // 如果去掉else,则编译器会报错 19 | /// x = 2; 20 | /// } 21 | /// println!("{}", x); // 如果去掉此行,再去掉else则不会报错,因为没有使用到x的地方,就算未初始化也没有关系 22 | /// } 23 | /// ``` 24 | /// 25 | /// Base usage: break会将分支中的变量返回 26 | /// ``` 27 | /// fn main() { 28 | /// let x: i32; 29 | /// loop { 30 | /// if true { 31 | /// x = 2; 32 | /// break; 33 | /// } 34 | /// } 35 | /// println!("{}", x); // 因为break会返回分支中的变量,所以该行可以正确打印2 36 | /// } 37 | /// ``` 38 | /// 39 | /// Base usage: 初始化数组 40 | /// ``` 41 | /// fn main() { 42 | /// let a: Vec = vec![]; // 必须指定类型,因为无法做类型推断 43 | /// let b: [i32; 0] = []; 44 | /// } 45 | /// ``` 46 | /// 47 | /// Base usage: 当将一个已初始化变量y绑定给另外一个变量y2时,Rust会把变量y看作是逻辑上的未初始化变量 48 | /// ``` 49 | /// fn main() { 50 | /// let x = 42; 51 | /// let y = Box::new(5); 52 | /// println!("{:p}", y); // 0x7f5ff041f008 53 | /// let x2 = x; 54 | /// let y2 = y; 55 | /// // println!("{:p}", y); // y实际上已经变成了未初始化变量 56 | /// } 57 | /// ``` 58 | pub fn binding_and_func(){ 59 | fn main() { 60 | let x: i32 = 1; 61 | println!("{}", x); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/ch05/borrow.rs: -------------------------------------------------------------------------------- 1 | /// # 借用与引用 2 | /// 3 | /// Base usage: 为函数传递数组,使用可变绑定作为参数 4 | /// 因为传入的是不可变,而经过函数参数的模式匹配,成为了可变参数 5 | /// ```rust 6 | /// fn foo(mut v: [i32; 3]) -> [i32; 3] { 7 | /// v[0] = 3; 8 | /// assert_eq!([3,2,3], v); 9 | /// v 10 | /// } 11 | /// fn main() { 12 | /// let v = [1,2,3]; 13 | /// foo(v); 14 | /// assert_eq!([1,2,3], v); 15 | /// } 16 | /// ``` 17 | /// 18 | /// Base usage: 以可变引用作为参数 19 | /// 20 | /// ```rust 21 | /// fn foo(v: &mut [i32; 3]) { 22 | /// v[0] = 3; 23 | /// } 24 | /// fn main() { 25 | /// let mut v = [1,2,3]; 26 | /// foo(&mut v); 27 | /// assert_eq!([3,2,3], v); 28 | /// } 29 | /// ``` 30 | pub fn borrow(){ 31 | fn foo(mut v: [i32; 3]) -> [i32; 3] { 32 | v[0] = 3; 33 | assert_eq!([3,2,3], v); 34 | v 35 | } 36 | fn main() { 37 | let v = [1,2,3]; 38 | foo(v); 39 | assert_eq!([1,2,3], v); 40 | } 41 | 42 | } 43 | 44 | /// # 借用与引用 45 | /// 46 | /// Base usage: 冒泡排序 47 | /// 48 | /// ```rust 49 | /// fn bubble_sort(a: &mut Vec) { 50 | /// let mut n = a.len(); // 获取数组长度 51 | /// while n > 0 { 52 | /// // 初始化遍历游标,max_ptr始终指向最大值 53 | /// let (mut i, mut max_ptr) = (1, 0); 54 | /// // 冒泡开始,如果前者大于后者则互换位置,并设置当前最大值游标 55 | /// while i < n { 56 | /// if a[i-1] > a[i] { 57 | /// a.swap(i-1, i); 58 | /// max_ptr = i; 59 | /// } 60 | /// i += 1; 61 | /// } 62 | /// // 本次遍历的最大值位置即是下一轮冒泡的终点 63 | /// n = max_ptr; 64 | /// } 65 | /// } 66 | /// fn main() { 67 | /// let mut a = vec![1, 4, 5, 3, 2]; 68 | /// bubble_sort(&mut a); 69 | /// println!("{:?}", a); // [1, 2, 3, 4, 5] 70 | /// } 71 | /// ``` 72 | pub fn bubble_sort_demo(){ 73 | fn bubble_sort(a: &mut Vec) { 74 | let mut n = a.len(); // 获取数组长度 75 | while n > 0 { 76 | // 初始化遍历游标,max_ptr始终指向最大值 77 | let (mut i, mut max_ptr) = (1, 0); 78 | // 冒泡开始,如果前者大于后者则互换位置,并设置当前最大值游标 79 | while i < n { 80 | if a[i-1] > a[i] { 81 | a.swap(i-1, i); 82 | max_ptr = i; 83 | } 84 | i += 1; 85 | } 86 | // 本次遍历的最大值位置即是下一轮冒泡的终点 87 | n = max_ptr; 88 | } 89 | } 90 | fn main() { 91 | let mut a = vec![1, 4, 5, 3, 2]; 92 | bubble_sort(&mut a); 93 | println!("{:?}", a); // [1, 2, 3, 4, 5] 94 | } 95 | 96 | } 97 | 98 | /// # 借用检查 99 | /// 100 | /// Base usage: 借用检查保证了内存安全 101 | /// 试想,input 和 output 如果将同一个变量的 不可变和可变引用同时传入会发生什么? 102 | /// 103 | /// ```rust 104 | /// fn compute(input: &u32, output: &mut u32) { 105 | /// if *input > 10 { 106 | /// *output = 1; 107 | /// } 108 | /// if *input > 5 { 109 | /// *output *= 2; 110 | /// } 111 | /// } 112 | /// fn main() { 113 | /// let i = 20; 114 | /// let mut o = 5; 115 | /// compute(&i, &mut o); // o = 2 116 | /// // let mut i = 20; 117 | /// // compute(&i, &mut i); // 借用检查不会允许该行编译成功 118 | 119 | /// } 120 | /// ``` 121 | /// 122 | /// Base usage: 优化该函数 123 | /// ``` 124 | /// fn compute(input: &u32, output: &mut u32) { 125 | /// let cached_input = *input; 126 | /// if cached_input > 10 { 127 | /// *output = 2; 128 | /// } else if cached_input > 5 { 129 | /// *output *= 2; 130 | /// } 131 | /// } 132 | /// fn main() { 133 | /// let i = 20; 134 | /// let mut o = 5; 135 | /// compute(&i, &mut o); // o = 2 136 | /// } 137 | /// ``` 138 | pub fn borrow_check(){ 139 | fn compute(input: &u32, output: &mut u32) { 140 | if *input > 10 { 141 | *output = 1; 142 | } 143 | if *input > 5 { 144 | *output *= 2; 145 | } 146 | } 147 | fn main() { 148 | let i = 20; 149 | let mut o = 5; 150 | compute(&i, &mut o); // o = 2 151 | } 152 | 153 | } 154 | 155 | /// # 解引用操作将获得所有权 156 | /// 157 | /// Base usage: 解引用移动语义类型需要注意 158 | /// 159 | /// ```rust 160 | /// fn join(s: &String) -> String { 161 | /// let append = *s; 162 | /// "Hello".to_string() + &append 163 | /// } 164 | /// fn main(){ 165 | /// let x = " hello".to_string(); 166 | /// join(&x); 167 | /// } 168 | /// ``` 169 | pub fn deref_move_type(){ 170 | // fn join(s: &String) -> String { 171 | // let append = *s; 172 | // "Hello".to_string() + &append 173 | // } 174 | // fn main(){ 175 | // let x = " hello".to_string(); 176 | // join(&x); 177 | // } 178 | } 179 | -------------------------------------------------------------------------------- /src/ch05/mod.rs: -------------------------------------------------------------------------------- 1 | //! 第五章:所有权系统 2 | //! 3 | 4 | /// # Examples 5 | /// 6 | /// Basic usage: 7 | /// 8 | /// ``` 9 | /// pub fn title(){ 10 | /// println!("第5章:{}", "所有权系统"); 11 | /// } 12 | /// title(); 13 | /// ``` 14 | pub fn title(){ 15 | println!("第5章:{}", "所有权系统"); 16 | } 17 | 18 | pub mod semantic; 19 | pub mod share_mutable; 20 | pub mod borrow; 21 | pub mod lifetime; 22 | pub mod nll; 23 | pub mod smart_pointer; 24 | -------------------------------------------------------------------------------- /src/ch05/semantic.rs: -------------------------------------------------------------------------------- 1 | /// # RAII自动资源管理 2 | /// 3 | /// Base usage: 等价C++代码 4 | /// ```c++ 5 | /// #include 6 | /// #include 7 | /// using namespace std; 8 | /// int main () 9 | /// { 10 | /// unique_ptr orig(new int(5)); 11 | /// cout << *orig << endl; 12 | /// auto stolen = move(orig); 13 | /// cout << *orig << endl; 14 | /// } 15 | /// ``` 16 | /// 17 | /// Base usage: 等价Rust代码 18 | /// ``` 19 | /// fn main() { 20 | /// let orig = Box::new(5); 21 | /// println!("{}", *orig); 22 | /// let stolen = orig; // orig 会move,因为是移动语义 23 | /// println!("{}", *orig); 24 | /// } 25 | /// ``` 26 | pub fn raii_demo(){ 27 | fn main() { 28 | let orig = Box::new(5); 29 | println!("{}", *orig); 30 | let stolen = orig; 31 | // println!("{}", *orig); 32 | } 33 | 34 | } 35 | 36 | /// # 值语义 == Copy语义 | 引用语义 == Move语义 37 | /// 38 | /// Base usage: 简单类型就是值语义,也就是Copy语义,因为可以安全在栈上进行复制 39 | /// ``` 40 | /// let x = 5; 41 | /// let y = x; 42 | /// assert_eq!(x, 5); 43 | /// assert_eq!(y, 5); 44 | /// ``` 45 | /// 46 | /// Base usage: 智能指针一般是引用语义,也就是Move语义,因为不能进行安全栈复制 47 | /// 以下会报错 48 | /// ``` 49 | /// // error[E0204]: the trait `Copy` may not be implemented for this type 50 | /// #[derive(Copy, Clone)] 51 | /// struct A{ 52 | /// a: i32, 53 | /// b: Box, 54 | /// } 55 | /// fn main(){} 56 | /// ``` 57 | pub fn value_semantic(){ 58 | let x = 5; 59 | let y = x; 60 | assert_eq!(x, 5); 61 | assert_eq!(y, 5); 62 | } 63 | 64 | /// # 所有权是否转移 65 | /// 66 | /// Base usage: 结构体默认没有实现Copy 67 | /// ``` 68 | /// #[derive(Debug)] 69 | /// struct A{ 70 | /// a: i32, 71 | /// b: u32, 72 | /// } 73 | /// fn main(){ 74 | /// let a = A {a: 1, b: 2}; 75 | /// let b = a; // a的所有权会转移 76 | /// println!("{:?}", a); 77 | /// } 78 | /// ``` 79 | /// 80 | /// Base usage: 手工为结构体实现Copy 81 | /// ``` 82 | /// #[derive(Debug, Copy, Clone)] 83 | /// struct A{ 84 | /// a: i32, 85 | /// b: u32, 86 | /// } 87 | /// fn main(){ 88 | /// let a = A {a: 1, b: 2}; 89 | /// let b = a; // a的所有权没有转移,因为这里是复制语义 90 | /// println!("{:?}", a); 91 | /// } 92 | /// ``` 93 | /// 94 | /// Base usage: 元组默认实现Copy 95 | /// ``` 96 | /// fn main(){ 97 | /// let a = ("a".to_string(), "b".to_string()); 98 | /// let b = a; // String是移动语义,所以此处a会移动 99 | /// // println!("{:?}", a); 100 | /// let c = (1,2,3); // 此处为复制语义 101 | /// let d = c; 102 | /// println!("{:?}", c); 103 | /// } 104 | /// ``` 105 | pub fn ownership_change(){ 106 | #[derive(Debug, Copy, Clone)] 107 | struct A{ 108 | a: i32, 109 | b: u32, 110 | } 111 | fn main(){ 112 | let a = A {a: 1, b: 2}; 113 | let b = a; 114 | println!("{:?}", a); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/ch05/share_mutable.rs: -------------------------------------------------------------------------------- 1 | /// # 可变与不可变 2 | /// 3 | /// Base usage: 绑定默认不可变 4 | /// ``` 5 | /// fn main() { 6 | /// let x = "hello".to_string(); 7 | /// // cannot borrow immutable local variable `x` as mutable 8 | /// // x += " world"; 9 | /// } 10 | /// ``` 11 | /// 12 | /// Base usage: 结构体默认没有实现Copy 13 | /// ``` 14 | /// fn main() { 15 | /// let mut x = "hello".to_string(); 16 | /// x += " world"; 17 | /// assert_eq!("hello world", x); 18 | /// } 19 | /// ``` 20 | pub fn immut_and_mut(){ 21 | fn main() { 22 | let x = "hello".to_string(); 23 | // cannot borrow immutable local variable `x` as mutable 24 | // x += " world"; 25 | } 26 | } 27 | 28 | /// # 词法作用域和生命周期 29 | /// 30 | /// Base usage: let 绑定会创造词法作用域 31 | /// ``` 32 | /// fn main(){ 33 | /// let a = "hello"; // -------scope a-------+ 34 | /// let b = "rust"; // -----scope b------+ | 35 | /// let c = "world"; // ---scope c ----+ | | 36 | /// let d = c; // - scope d --- | | | 37 | /// } //----------------------------------+--+--+--+ 38 | /// ``` 39 | /// 40 | /// Base usage: 花括号创造词法作用域 41 | /// ``` 42 | /// fn main(){ 43 | /// let outer_val = 1; 44 | /// let outer_sp = "hello".to_string(); 45 | /// { 46 | /// let inner_val = 2; 47 | /// outer_val; 48 | /// outer_sp; 49 | /// } 50 | /// println!("{:?}", outer_val); 51 | /// // error[E0425]: cannot find value `inner_val` in this scope 52 | /// // println!("{:?}", inner_val); 53 | /// // error[E0382]: use of moved value: `outer_sp` 54 | /// // println!("{:?}", outer_sp); 55 | /// } 56 | /// ``` 57 | /// 58 | /// Base usage: match匹配的花括号创造词法作用域 59 | /// ``` 60 | /// fn main(){ 61 | /// let a = Some("hello".to_string()); 62 | /// match a { // ------------------------------ 63 | /// Some(s) => println!("{:?}", s), // | match scope 64 | /// _ => println!("nothing") // | 65 | /// } // -------------------------------------- 66 | /// // error[E0382]: use of partially moved value: `a` 67 | /// // println!("{:?}", a); 68 | /// } 69 | /// ``` 70 | /// 71 | /// Base usage: 循环表达式花括号创造词法作用域 72 | /// ``` 73 | /// fn main(){ 74 | /// let v = vec![1,2,3]; 75 | /// for i in v { // ------------------------------------ 76 | /// println!("{:?}", i); // | 77 | /// // error[E0382]: use of moved value: `v` // | for scope 78 | /// // println!("{:?}", v); // | 79 | /// } //----------------------------------------------- 80 | /// } 81 | /// ``` 82 | /// 83 | /// Base usage: if let表达式花括号创造词法作用域 84 | /// ``` 85 | /// fn main(){ 86 | /// let a = Some("hello".to_string()); 87 | /// if let Some(s) = a { // ------- 88 | /// println!("{:?}", s) //| if let scope 89 | /// } //--------------------------- 90 | /// } 91 | /// ``` 92 | /// 93 | /// Base usage: while let表达式花括号创造词法作用域 94 | /// ``` 95 | /// fn main() { 96 | /// let mut optional = Some(0); 97 | /// while let Some(i) = optional { // ------------------ ----+ 98 | /// if i > 9 { // | 99 | /// println!("Greater than 9, quit!"); // | 100 | /// optional = None; // | 101 | /// } else { // | while scope 102 | /// println!("`i` is `{:?}`. Try again.", i);// | 103 | /// optional = Some(i + 1); // | 104 | /// } // | 105 | /// } // ----------------------------------------------------+ 106 | /// } 107 | /// ``` 108 | /// 109 | /// Base usage: 函数花括号创造词法作用域 110 | /// ``` 111 | /// fn foo(s: String) -> String { // ---- 112 | /// let w = " world".to_string(); // | function scope 113 | /// s + &w // | 114 | /// } // -------------------------------- 115 | /// fn main() { 116 | /// let s = "hello".to_string(); 117 | /// let ss = foo(s); 118 | /// // println!("{:?}", s) // Error: use of moved value: `s` 119 | /// } 120 | /// ``` 121 | /// 122 | /// Base usage: 闭包 123 | /// ``` 124 | /// fn main() { 125 | /// let s = "hello".to_string(); 126 | /// let join = |i: &str| {s + i}; // moved s into closure scope 127 | /// assert_eq!("hello world", join(" world")); 128 | /// // println!("{:?}", s); // error[E0382]: use of moved value: `s` 129 | /// } 130 | /// ``` 131 | pub fn lexical_scope(){ 132 | fn main(){ 133 | let a = "hello"; // -------scope a-------+ 134 | let b = "rust"; // -----scope b------+ | 135 | let c = "world"; // ---scope c ----+ | | 136 | let d = c; // - scope d --- | | | 137 | } //----------------------------------+--+--+--+ 138 | } 139 | -------------------------------------------------------------------------------- /src/ch06/mod.rs: -------------------------------------------------------------------------------- 1 | //!第六章:函数、闭包和迭代器 2 | //! 3 | 4 | /// # Examples 5 | /// 6 | /// Basic usage: 7 | /// 8 | /// ``` 9 | /// pub fn title(){ 10 | /// println!("第6章:{}", "函数、闭包和迭代器"); 11 | /// } 12 | /// title(); 13 | /// ``` 14 | pub fn title(){ 15 | println!("第6章:{}", "函数、闭包和迭代器"); 16 | } 17 | 18 | pub mod functions; 19 | pub mod closures; 20 | pub mod iters; 21 | -------------------------------------------------------------------------------- /src/ch07/mod.rs: -------------------------------------------------------------------------------- 1 | //! 第七章:结构化编程 2 | //! 3 | 4 | /// # Examples 5 | /// 6 | /// Basic usage: 7 | /// 8 | /// ``` 9 | /// pub fn title(){ 10 | /// println!("第7章:{}", "结构化编程"); 11 | /// } 12 | /// title(); 13 | /// ``` 14 | pub fn title(){ 15 | println!("第7章:{}", "结构化编程"); 16 | } 17 | 18 | pub mod structs; 19 | pub mod design_pattern; 20 | -------------------------------------------------------------------------------- /src/ch08/bases.rs: -------------------------------------------------------------------------------- 1 | /// # 字符串编码 2 | /// 3 | /// Base usage: 从Unicode到UTF-8编码过程 4 | /// 5 | /// ```rust 6 | /// use std::str; 7 | /// fn main() { 8 | /// let tao = str::from_utf8(&[0xE9u8, 0x81u8, 0x93u8]).unwrap(); // 将UTF-8序列转为字符串 9 | /// assert_eq!("道", tao); 10 | /// assert_eq!("道", String::from("\u{9053}")); // 将16进制Unicode码位转为字符串 11 | /// let unicode_x = 0x9053; 12 | /// let utf_x_hex = 0xe98193; 13 | /// let utf_x_bin = 0b111010011000000110010011; 14 | /// println!("unicode_x: {:b}", unicode_x); 15 | /// println!("utf_x_hex: {:b}", utf_x_hex); 16 | /// println!("utf_x_bin: 0x{:x}", utf_x_bin); 17 | /// } 18 | /// ``` 19 | /// 20 | /// Base usage: 字符与Unicode标量值一一对应 21 | /// 22 | /// ```rust 23 | /// fn main() { 24 | /// let tao = '道'; 25 | /// let tao_u32 = tao as u32; 26 | /// assert_eq!(36947, tao_u32); 27 | /// println!("U+{:x}", tao_u32); // U+9053 28 | /// println!("{}", tao.escape_unicode()); //\u{9053} 29 | /// assert_eq!(char::from(65), 'A'); 30 | /// assert_eq!(std::char::from_u32(0x9053), Some('道')); 31 | /// assert_eq!(std::char::from_u32(36947), Some('道')); 32 | /// assert_eq!(std::char::from_u32(12901010101), None); // 该数字并不是一个有效的Unicode标量值 33 | /// } 34 | /// ``` 35 | /// 36 | /// Base usage: 将字符转为字符串要注意字节长度 37 | /// 38 | /// ```rust 39 | /// fn main() { 40 | /// let mut b = [0; 3]; 41 | /// let tao = '道'; 42 | /// assert_eq!(4, tao.len_utf8()); 43 | /// let tao_str = tao.encode_utf8(&mut b); // 将tao转为字符串tao_str 44 | /// assert_eq!("道", tao_str); 45 | /// assert_eq!(3, tao.len_utf8()); 46 | /// } 47 | /// ``` 48 | /// 49 | /// Base usage: 包含单个码位的才能声明为字符 50 | /// 51 | /// 特此说明:在Rust 1.30版下面代码将不会报错,将支持多码位字符 52 | /// 53 | /// ```rust 54 | /// fn main() { 55 | /// let e = 'é'; // Error: 此处包含两个码位 56 | /// println!("{}", e as u32); 57 | /// } 58 | /// ``` 59 | /// 60 | /// 61 | /// Base usage: 展示char类型的内建方法 62 | /// 63 | /// ```rust 64 | /// fn main(){ 65 | /// assert_eq!(true, 'f'.is_digit(16)); 66 | /// assert_eq!(Some(15), 'f'.to_digit(16)); 67 | /// assert!('a'.is_lowercase()); 68 | /// assert!(!'道'.is_lowercase()); 69 | /// assert!(!'a'.is_uppercase()); 70 | /// assert!('A'.is_uppercase()); 71 | /// assert!(!'中'.is_uppercase()); 72 | /// assert_eq!('i', 'I'.to_lowercase()); 73 | /// assert_eq!('B', 'b'.to_uppercase()); 74 | /// assert!(' '.is_whitespace()); 75 | /// assert!('\u{A0}'.is_whitespace()); 76 | /// assert!(!'越'.is_whitespace()); 77 | /// assert!('a'.is_alphabetic()); 78 | /// assert!('京'.is_alphabetic()); 79 | /// assert!(!'1'.is_alphabetic()); 80 | /// assert!('7'.is_alphanumeric()); 81 | /// assert!('K'.is_alphanumeric()); 82 | /// assert!('藏'.is_alphanumeric()); 83 | /// assert!(!'¾'.is_alphanumeric()); 84 | /// assert!('œ'.is_control()); 85 | /// assert!(!'q'.is_control()); 86 | /// assert!('٣'.is_numeric()); 87 | /// assert!('7'.is_numeric()); 88 | /// assert!(!'و'.is_numeric()); 89 | /// assert!(!'藏'.is_numeric()); 90 | /// println!("{}", '\r'.escape_default()); 91 | /// } 92 | /// ``` 93 | 94 | pub fn bases(){ 95 | unimplemented!(); 96 | } 97 | -------------------------------------------------------------------------------- /src/ch08/hashmaps.rs: -------------------------------------------------------------------------------- 1 | /// # HashMap 2 | /// 3 | /// Base usage: 增删改查 4 | /// 5 | /// ```rust 6 | /// use std::collections::HashMap; 7 | /// fn main() { 8 | /// let mut book_reviews = HashMap::with_capacity(10); 9 | /// book_reviews.insert("Rust Book", "good"); 10 | /// book_reviews.insert("Programming Rust", "nice"); 11 | /// book_reviews.insert("The Tao of Rust", "deep"); 12 | /// for key in book_reviews.keys() { 13 | /// println!("{}", key); 14 | /// } 15 | /// for val in book_reviews.values() { 16 | /// println!("{}", val); 17 | /// } 18 | /// if !book_reviews.contains_key("rust book") { 19 | /// println!("find {} times ", book_reviews.len()); 20 | /// } 21 | /// book_reviews.remove("Rust Book"); 22 | /// let to_find = ["Rust Book", "The Tao of Rust"]; 23 | /// for book in &to_find { 24 | /// match book_reviews.get(book) { 25 | /// Some(review) => println!("{}: {}", book, review), 26 | /// None => println!("{} is unreviewed.", book), 27 | /// } 28 | /// } 29 | /// for (book, review) in &book_reviews { 30 | /// println!("{}: \"{}\"", book, review); 31 | /// } 32 | /// assert_eq!(book_reviews["The Tao of Rust"], "deep"); 33 | /// } 34 | /// ``` 35 | /// 36 | /// Base usage: Entry模式 37 | /// 38 | /// ```rust 39 | /// use std::collections::HashMap; 40 | /// fn main() { 41 | /// let mut map: HashMap<&str, u32> = HashMap::new(); 42 | /// map.entry("current_year").or_insert(2017); 43 | /// assert_eq!(map["current_year"], 2017); 44 | /// *map.entry("current_year").or_insert(2017) += 10; 45 | /// assert_eq!(map["current_year"], 2027); 46 | /// let last_leap_year = 2016; 47 | /// map.entry("next_leap_year") 48 | /// .or_insert_with(|| last_leap_year + 4 ); 49 | /// assert_eq!(map["next_leap_year"], 2020); 50 | /// assert_eq!(map.entry("current_year").key(), &"current_year"); 51 | /// } 52 | /// ``` 53 | /// 54 | /// Base usage: HashMap的三种合并方式 55 | /// 56 | /// ```rust 57 | /// use std::collections::HashMap; 58 | /// fn merge_extend<'a>( 59 | /// map1: &mut HashMap<&'a str, &'a str>, 60 | /// map2: HashMap<&'a str, &'a str> 61 | /// ) { 62 | /// map1.extend(map2); 63 | /// } 64 | /// fn merge_chain<'a>( 65 | /// map1: HashMap<&'a str, &'a str>, 66 | /// map2: HashMap<&'a str, &'a str> 67 | /// ) -> HashMap<&'a str, &'a str> { 68 | /// map1.into_iter().chain(map2).collect() 69 | /// } 70 | /// fn merge_by_ref<'a>( 71 | /// map: &mut HashMap<&'a str, &'a str>, 72 | /// map_ref: &HashMap<&'a str, &'a str> 73 | /// ){ 74 | /// map.extend(map_ref.into_iter() 75 | /// .map(|(k, v)| (k.clone(), v.clone())) 76 | /// ); 77 | /// } 78 | /// fn main() { 79 | /// let mut book_reviews1 = HashMap::new(); 80 | /// book_reviews1.insert("Rust Book", "good"); 81 | /// book_reviews1.insert("Programming Rust", "nice"); 82 | /// book_reviews1.insert("The Tao of Rust", "deep"); 83 | /// let mut book_reviews2 = HashMap::new(); 84 | /// book_reviews2.insert("Rust in Action", "good"); 85 | /// book_reviews2.insert("Rust Primer", "nice"); 86 | /// book_reviews2.insert("Matering Rust", "deep"); 87 | /// // merge_extend(&mut book_reviews1, book_reviews2); 88 | /// // let book_reviews1 = merge_chain(book_reviews1, book_reviews2); 89 | /// merge_by_ref(&mut book_reviews1, &book_reviews2); 90 | /// for key in book_reviews1.keys() { 91 | /// println!("{}", key); 92 | /// } 93 | /// } 94 | /// ``` 95 | pub fn hashmaps(){ 96 | unimplemented!(); 97 | } 98 | -------------------------------------------------------------------------------- /src/ch08/mod.rs: -------------------------------------------------------------------------------- 1 | //! 第八章:字符串与集合 2 | //! 3 | 4 | /// # Examples 5 | /// 6 | /// Basic usage: 7 | /// 8 | /// ``` 9 | /// pub fn title(){ 10 | /// println!("第8章:{}", "字符串与集合"); 11 | /// } 12 | /// title(); 13 | /// ``` 14 | pub fn title(){ 15 | println!("第8章:{}", "字符串与集合"); 16 | } 17 | 18 | pub mod bases; 19 | pub mod strings; 20 | pub mod vectors; 21 | pub mod hashmaps; 22 | -------------------------------------------------------------------------------- /src/ch09/examples/io_origin.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::error::Error; 3 | use std::fs::File; 4 | use std::io::prelude::*; 5 | use std::process; 6 | type ParseResult = Result>; 7 | fn run(filename: &str) -> ParseResult { 8 | File::open(filename).map_err(|e| e.into()) 9 | .and_then(|mut f|{ 10 | let mut contents = String::new(); 11 | f.read_to_string(&mut contents) 12 | .map_err(|e| e.into()).map(|_|contents) 13 | }) 14 | .and_then(|contents|{ 15 | let mut sum = 0; 16 | for c in contents.lines(){ 17 | match c.parse::() { 18 | Ok(n) => {sum += n;}, 19 | Err(err) => { 20 | let err: Box = err.into(); 21 | println!("error info: {}, cause: {:?}" 22 | , err.description(),err.cause()); 23 | }, 24 | // Err(err) => { return Err(From::from(err));}, 25 | } 26 | } 27 | Ok(sum) 28 | }) 29 | } 30 | fn main() { 31 | let args: Vec = env::args().collect(); 32 | let filename = &args[1]; 33 | println!("In file {}", filename); 34 | match run(filename) { 35 | Ok(n) => { println!("{:?}", n); }, 36 | Err(e) => { 37 | println!("main error: {}", e); 38 | process::exit(1); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/ch09/examples/io_origin_refactor.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::error::Error; 3 | use std::fs::File; 4 | use std::io::prelude::*; 5 | use std::process; 6 | use std::io; 7 | use std::num; 8 | use std::fmt; 9 | #[derive(Debug)] 10 | enum CliError { 11 | Io(io::Error), 12 | Parse(num::ParseIntError), 13 | } 14 | 15 | impl fmt::Display for CliError { 16 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 17 | match *self { 18 | CliError::Io(ref err) => write!(f, "IO error: {}", err), 19 | CliError::Parse(ref err) => write!(f, "Parse error: {}", err), 20 | } 21 | } 22 | } 23 | 24 | impl Error for CliError { 25 | fn description(&self) -> &str { 26 | match *self { 27 | CliError::Io(ref err) => err.description(), 28 | CliError::Parse(ref err) => Error::description(err), 29 | } 30 | } 31 | 32 | fn cause(&self) -> Option<&Error> { 33 | match *self { 34 | CliError::Io(ref err) => Some(err), 35 | CliError::Parse(ref err) => Some(err), 36 | } 37 | } 38 | } 39 | impl From for CliError { 40 | fn from(err: io::Error) -> CliError { 41 | CliError::Io(err) 42 | } 43 | } 44 | impl From for CliError { 45 | fn from(err: num::ParseIntError) -> CliError { 46 | CliError::Parse(err) 47 | } 48 | } 49 | fn run(filename: Option) -> ParseResult { 50 | let mut file = File::open(filename.unwrap())?; 51 | 52 | let mut contents = String::new(); 53 | file.read_to_string(&mut contents)?; 54 | let mut sum = 0; 55 | for c in contents.lines(){ 56 | let n: i32 = c.parse::()?; 57 | sum += n; 58 | } 59 | Ok(sum) 60 | } 61 | type ParseResult = Result; 62 | fn main() { 63 | let filename = env::args().nth(1); 64 | match run(filename) { 65 | Ok(n) => { 66 | println!("{:?}", n); 67 | }, 68 | Err(e) => { 69 | println!("main error: {}", e); 70 | process::exit(1); 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/ch09/examples/io_origin_refactor3.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::error::Error; 3 | use std::fs::File; 4 | use std::io::prelude::*; 5 | use std::process; 6 | use std::io; 7 | use std::num; 8 | use std::fmt; 9 | 10 | #[derive(Debug)] 11 | enum CliError { 12 | Io(io::Error), 13 | Parse(num::ParseIntError), 14 | } 15 | 16 | impl fmt::Display for CliError { 17 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 18 | match *self { 19 | CliError::Io(ref err) => write!(f, "IO error: {}", err), 20 | CliError::Parse(ref err) => write!(f, "Parse error: {}", err), 21 | } 22 | } 23 | } 24 | 25 | impl Error for CliError { 26 | fn description(&self) -> &str { 27 | match *self { 28 | CliError::Io(ref err) => err.description(), 29 | CliError::Parse(ref err) => Error::description(err), 30 | } 31 | } 32 | 33 | fn cause(&self) -> Option<&Error> { 34 | match *self { 35 | CliError::Io(ref err) => Some(err), 36 | CliError::Parse(ref err) => Some(err), 37 | } 38 | } 39 | } 40 | impl From for CliError { 41 | fn from(err: io::Error) -> CliError { 42 | CliError::Io(err) 43 | } 44 | } 45 | impl From for CliError { 46 | fn from(err: num::ParseIntError) -> CliError { 47 | CliError::Parse(err) 48 | } 49 | } 50 | fn run(filename: &str) -> ParseResult { 51 | let mut file = File::open(filename)?; 52 | 53 | let mut contents = String::new(); 54 | file.read_to_string(&mut contents)?; 55 | let mut sum = 0; 56 | for c in contents.lines(){ 57 | let n: i32 = c.parse::()?; 58 | sum += n; 59 | } 60 | Ok(sum) 61 | } 62 | type ParseResult = Result; 63 | 64 | fn main() { 65 | let args: Vec = env::args().collect(); 66 | let filename = &args[1]; 67 | println!("In file {}", filename); 68 | 69 | match run(filename) { 70 | Ok(n) => { 71 | println!("{:?}", n); 72 | }, 73 | Err(e) => { 74 | println!("main error: {}", e); 75 | process::exit(1); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /src/ch09/examples/io_origin_refactor4.rs: -------------------------------------------------------------------------------- 1 | #![feature(try_trait)] 2 | use std::env; 3 | use std::error::Error; 4 | use std::fs::File; 5 | use std::io::prelude::*; 6 | use std::process; 7 | use std::io; 8 | use std::num; 9 | use std::fmt; 10 | use std::option::NoneError; 11 | 12 | #[derive(Debug)] 13 | enum CliError { 14 | Io(io::Error), 15 | Parse(num::ParseIntError), 16 | NoneError(NoneError), 17 | } 18 | impl fmt::Display for CliError { 19 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 20 | match *self { 21 | CliError::Io(ref err) => write!(f, "IO error: {}", err), 22 | CliError::Parse(ref err) => write!(f, "Parse error: {}", err), 23 | CliError::NoneError(ref err) => write!(f, "Command args error: {:?}", err), 24 | } 25 | } 26 | } 27 | impl Error for CliError { 28 | fn description(&self) -> &str { 29 | match *self { 30 | CliError::Io(ref err) => err.description(), 31 | CliError::Parse(ref err) => Error::description(err), 32 | CliError::NoneError(ref err) => "NoneError", 33 | } 34 | } 35 | fn cause(&self) -> Option<&Error> { 36 | match *self { 37 | CliError::Io(ref err) => Some(err), 38 | CliError::Parse(ref err) => Some(err), 39 | _ => None, 40 | } 41 | } 42 | } 43 | 44 | impl From for CliError { 45 | fn from(err: io::Error) -> CliError { 46 | CliError::Io(err) 47 | } 48 | } 49 | 50 | 51 | impl From for CliError { 52 | fn from(err: NoneError) -> CliError { 53 | CliError::NoneError(err) 54 | } 55 | } 56 | 57 | impl From for CliError { 58 | fn from(err: num::ParseIntError) -> CliError { 59 | CliError::Parse(err) 60 | } 61 | } 62 | 63 | fn run(filename: Option) -> ParseResult { 64 | let mut file = File::open(filename?)?; 65 | let mut contents = String::new(); 66 | file.read_to_string(&mut contents)?; 67 | let mut sum = 0; 68 | for c in contents.lines(){ 69 | let n: i32 = c.parse::()?; 70 | sum += n; 71 | } 72 | Ok(sum) 73 | } 74 | 75 | type ParseResult = Result; 76 | 77 | fn main() { 78 | let filename = env::args().nth(1); 79 | match run(filename) { 80 | Ok(n) => { 81 | println!("{:?}", n); 82 | }, 83 | Err(e) => { 84 | eprintln!("main error: {}", e); 85 | process::exit(1); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /src/ch09/examples/test_txt: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 -------------------------------------------------------------------------------- /src/ch09/failures.rs: -------------------------------------------------------------------------------- 1 | /// # 消除失败 2 | /// 3 | /// 1. 利用类型系统 4 | /// 2. 利用断言 5 | /// 6 | /// Base usage: 利用类型系统消除程序中的失败 7 | /// 8 | /// ```rust 9 | /// fn sum(a: i32, b: i32) -> i32 { 10 | /// a + b 11 | /// } 12 | /// fn main() { 13 | /// sum(1u32, 2u32); // 违反契约,报错 14 | /// } 15 | /// ``` 16 | /// 17 | /// Base usage: 利用断言消除运行时failure 18 | /// 19 | /// ```rust 20 | /// fn main() { 21 | /// let mut vec = vec![1, 2, 3]; 22 | /// vec.insert(1, 4); 23 | /// assert_eq!(vec, [1, 4, 2, 3]); 24 | /// vec.insert(4, 5); 25 | /// assert_eq!(vec, [1, 4, 2, 3, 5]); 26 | /// // vec.insert(8, 8); 27 | /// } 28 | /// ``` 29 | pub fn eliminate_failure(){ 30 | unimplemented!(); 31 | } 32 | -------------------------------------------------------------------------------- /src/ch09/failures_crate/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /src/ch09/failures_crate/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "failures_crate" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | description = "《Rust编程之道》随书源码之failures crate" 7 | homepage = "https://github.com/ZhangHanDong/tao-of-rust-codes" 8 | documentation = "https://docs.rs/crate/tao-of-rust/" 9 | repository = "https://github.com/ZhangHanDong/tao-of-rust-codes" 10 | license = "MIT" 11 | keywords = ["book"] 12 | categories = ["rust-programming-book-codes"] 13 | 14 | [dependencies] 15 | failure="0.1.2" 16 | failure_derive="0.1.2" 17 | -------------------------------------------------------------------------------- /src/ch09/failures_crate/README.md: -------------------------------------------------------------------------------- 1 | # 执行 2 | 3 | ``` 4 | $ cargo run src/text_test 5 | ``` -------------------------------------------------------------------------------- /src/ch09/failures_crate/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # failure 使用代码示例 2 | //! 3 | //! 使用第三方failure库统一管理错误 4 | // extern crate failure; 5 | // #[macro_use] extern crate failure_derive; 6 | 7 | use failure::{Backtrace, Context, Fail}; 8 | use std::fs::File; 9 | use std::io::prelude::*; 10 | 11 | /// # 使用Error来统一管理错误 12 | #[derive(Debug)] 13 | pub struct Error { 14 | inner: Context, 15 | } 16 | /// # ErrorKind记录各种错误 17 | #[derive(Debug, Fail)] 18 | pub enum ErrorKind { 19 | #[fail(display = "IoError")] 20 | Io(#[cause] std::io::Error), 21 | #[fail(display = "ParseError")] 22 | Parse(#[cause] std::num::ParseIntError), 23 | // ADD new Error Kind 24 | } 25 | 26 | impl Fail for Error { 27 | fn cause(&self) -> Option<&Fail> { 28 | self.inner.cause() 29 | } 30 | fn backtrace(&self) -> Option<&Backtrace> { 31 | self.inner.backtrace() 32 | } 33 | } 34 | 35 | impl std::fmt::Display for Error { 36 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 37 | std::fmt::Display::fmt(&self.inner, f) 38 | } 39 | } 40 | 41 | impl From for Error { 42 | fn from(err: std::io::Error) -> Error { 43 | Error { 44 | inner: Context::new(ErrorKind::Io(err)), 45 | } 46 | } 47 | } 48 | 49 | impl From for Error { 50 | fn from(err: std::num::ParseIntError) -> Error { 51 | Error { 52 | inner: Context::new(ErrorKind::Parse(err)), 53 | } 54 | } 55 | } 56 | 57 | type ParseResult = Result; 58 | 59 | pub fn run(filename: Option) -> ParseResult { 60 | let mut file = File::open(filename.unwrap())?; 61 | 62 | let mut contents = String::new(); 63 | file.read_to_string(&mut contents)?; 64 | let mut sum = 0; 65 | for c in contents.lines() { 66 | let n: i32 = c.parse::()?; 67 | sum += n; 68 | } 69 | Ok(sum) 70 | } 71 | -------------------------------------------------------------------------------- /src/ch09/failures_crate/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate failures_crate; 2 | use failures_crate::*; 3 | use std::env; 4 | fn main() -> Result<(), String> { 5 | let filename = env::args().nth(1); 6 | match failures_crate::run(filename) { 7 | Ok(n) => { 8 | println!("{:?}", n); 9 | return Ok(()); 10 | }, 11 | Err(e) => { 12 | return Err("1".to_string()); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/ch09/failures_crate/src/text_test: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | -------------------------------------------------------------------------------- /src/ch09/mod.rs: -------------------------------------------------------------------------------- 1 | //! 第九章:构建健壮的程序 2 | //! 3 | 4 | /// # Examples 5 | /// 6 | /// Basic usage: 7 | /// 8 | /// ``` 9 | /// pub fn title(){ 10 | /// println!("第9章:{}", "构建健壮的程序"); 11 | /// } 12 | /// title(); 13 | /// ``` 14 | extern crate failures_crate; 15 | 16 | pub fn title(){ 17 | println!("第9章:{}", "构建健壮的程序"); 18 | } 19 | 20 | pub mod failures; 21 | pub mod errors; 22 | pub mod panics; 23 | -------------------------------------------------------------------------------- /src/ch09/panics.rs: -------------------------------------------------------------------------------- 1 | /// # 恐慌 2 | /// 3 | /// 1. 了解恐慌安全 4 | /// 2. catch_unwind 5 | /// 6 | /// Base usage: 使用catch_unwind 7 | /// 8 | /// ```rust 9 | /// use std::panic; 10 | /// fn sum(a: i32, b: i32) -> i32{ 11 | /// a + b 12 | /// } 13 | /// fn main() { 14 | /// let result = panic::catch_unwind(|| { println!("hello!"); }); 15 | /// assert!(result.is_ok()); 16 | /// let result = panic::catch_unwind(|| { panic!("oh no!"); }); 17 | /// assert!(result.is_err()); 18 | /// println!("{}", sum(1, 2)); 19 | /// } 20 | /// ``` 21 | /// 22 | /// Base usage: 使用set_hook 23 | /// 24 | /// ```rust 25 | /// use std::panic; 26 | /// fn sum(a: i32, b: i32) -> i32{ 27 | /// a + b 28 | /// } 29 | /// fn main() { 30 | /// let result = panic::catch_unwind(|| { println!("hello!"); }); 31 | /// assert!(result.is_ok()); 32 | /// panic::set_hook(Box::new(|panic_info| { 33 | /// if let Some(location) = panic_info.location() { 34 | /// println!("panic occurred '{}' at {}", 35 | /// location.file(), location.line() 36 | /// ); 37 | /// } else { 38 | /// println!("can't get location information..."); 39 | /// } 40 | /// })); 41 | /// let result = panic::catch_unwind(|| { panic!("oh no!"); }); 42 | /// assert!(result.is_err()); 43 | /// println!("{}", sum(1, 2)); 44 | /// } 45 | /// ``` 46 | pub fn panics(){ 47 | unimplemented!(); 48 | } 49 | -------------------------------------------------------------------------------- /src/ch10/csv-read/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /src/ch10/csv-read/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "csv-read" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /src/ch10/csv-read/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/ch10/csv_challenge/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /src/ch10/csv_challenge/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "csv_challenge" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | description = "《Rust编程之道》随书源码之CSV挑战" 7 | homepage = "https://github.com/ZhangHanDong/tao-of-rust-codes" 8 | documentation = "https://docs.rs/crate/tao-of-rust/" 9 | repository = "https://github.com/ZhangHanDong/tao-of-rust-codes" 10 | license = "MIT" 11 | keywords = ["book"] 12 | categories = ["rust-programming-book-codes"] 13 | 14 | [dependencies] 15 | structopt = "0.2" 16 | structopt-derive = "0.2" 17 | -------------------------------------------------------------------------------- /src/ch10/csv_challenge/README.md: -------------------------------------------------------------------------------- 1 | # 说明 2 | 3 | ``` 4 | $ cargo run input/challenge.csv City Beijing 5 | ``` -------------------------------------------------------------------------------- /src/ch10/csv_challenge/benches/file_op_bench.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | extern crate test; 3 | use test::Bencher; 4 | use std::path::PathBuf; 5 | use csv_challenge::{ 6 | Opt, 7 | {load_csv, write_csv}, 8 | replace_column, 9 | }; 10 | #[bench] 11 | fn bench_read_100times(b: &mut Bencher) { 12 | b.iter(|| { 13 | let n = test::black_box(100); 14 | (0..n).fold(0, |_,_|{test_load_csv();0}) 15 | }); 16 | } 17 | fn test_load_csv(){ 18 | let filename = PathBuf::from("./input/challenge.csv"); 19 | load_csv(filename); 20 | } 21 | #[bench] 22 | fn bench_rw_100times(b: &mut Bencher) { 23 | b.iter(|| { 24 | let n = test::black_box(100); 25 | (0..n).fold(0, |_,_|{test_read_write_csv();0}) 26 | }); 27 | } 28 | 29 | fn test_read_write_csv(){ 30 | let filename = PathBuf::from("./input/challenge.csv"); 31 | let csv_data = load_csv(filename).unwrap(); 32 | let modified_data = replace_column(csv_data, "City", "Beijing").unwrap(); 33 | write_csv(&modified_data, "output/test.csv"); 34 | } 35 | -------------------------------------------------------------------------------- /src/ch10/csv_challenge/input/challenge.csv: -------------------------------------------------------------------------------- 1 | First Name,Last Name,Age,City,Eyes color,Species 2 | John,Doe,32,Tokyo,Blue,Human 3 | Flip,Helm,12,Canberra,Red,Unknown 4 | Terdos,Bendarian,165,Cracow,Blue,Magic tree 5 | Dominik,Elpos,33,Paris,Purple,Orc 6 | Brad,Doe,42,Dublin,Blue,Human 7 | Ewan,Grath,51,New Delhi,Green,Human 8 | -------------------------------------------------------------------------------- /src/ch10/csv_challenge/input/no_header.csv: -------------------------------------------------------------------------------- 1 | John,Doe,32,Tokyo,Blue,Human 2 | Flip,Helm,12,Canberra,Red,Unknown 3 | Terdos,Bendarian,165,Cracow,Blue,Magic tree 4 | Dominik,Elpos,33,Paris,Purple,Orc 5 | Brad,Doe,42,Dublin,Blue,Human 6 | Ewan,Grath,51,New Delhi,Green,Human 7 | -------------------------------------------------------------------------------- /src/ch10/csv_challenge/output/output.csv: -------------------------------------------------------------------------------- 1 | First Name,Last Name,Age,City,Eyes color,Species 2 | John,Doe,32,Beijing,Blue,Human 3 | Flip,Helm,12,Beijing,Red,Unknown 4 | Terdos,Bendarian,165,Beijing,Blue,Magic tree 5 | Dominik,Elpos,33,Beijing,Purple,Orc 6 | Brad,Doe,42,Beijing,Blue,Human 7 | Ewan,Grath,51,Beijing,Green,Human 8 | -------------------------------------------------------------------------------- /src/ch10/csv_challenge/output/test.csv: -------------------------------------------------------------------------------- 1 | First Name,Last Name,Age,City,Eyes color,Species 2 | John,Doe,32,Beijing,Blue,Human 3 | Flip,Helm,12,Beijing,Red,Unknown 4 | Terdos,Bendarian,165,Beijing,Blue,Magic tree 5 | Dominik,Elpos,33,Beijing,Purple,Orc 6 | Brad,Doe,42,Beijing,Blue,Human 7 | Ewan,Grath,51,Beijing,Green,Human 8 | -------------------------------------------------------------------------------- /src/ch10/csv_challenge/src/core.rs: -------------------------------------------------------------------------------- 1 | pub mod read; 2 | pub mod write; 3 | use crate::err::Error; 4 | use std::{ 5 | path::PathBuf, 6 | fs::File, 7 | io::{Read, Write}, 8 | }; 9 | -------------------------------------------------------------------------------- /src/ch10/csv_challenge/src/core/read.rs: -------------------------------------------------------------------------------- 1 | use super::{Error, PathBuf, File, Read, Write}; 2 | 3 | /// # Usage: 4 | /// ```ignore 5 | /// use std::path::PathBuf; 6 | /// let filename = PathBuf::from("./files/challenge.csv"); 7 | /// let csv_data = load_csv(filename); 8 | /// assert!(csv_data.is_ok()); 9 | /// ``` 10 | pub fn load_csv(csv_file: PathBuf) -> Result { 11 | let file = read(csv_file)?; 12 | Ok(file) 13 | } 14 | 15 | /// # Usage: 16 | /// ```ignore 17 | /// let filename = PathBuf::from("./files/challenge.csv"); 18 | /// let csv_data = load_csv(filename).unwrap(); 19 | /// let modified_data = replace_column(csv_data, "City", "Beijing").unwrap(); 20 | /// let output_file = write_csv(&modified_data, "output/test.csv"); 21 | /// assert!(output_file.is_ok()); 22 | /// ``` 23 | pub fn write_csv(csv_data: &str, filename: &str) -> Result<(), Error> 24 | { 25 | write(csv_data, filename)?; 26 | Ok(()) 27 | } 28 | fn read(path: PathBuf) -> Result { 29 | let mut buffer = String::new(); 30 | let mut file = open(path)?; 31 | file.read_to_string(&mut buffer)?; 32 | if buffer.is_empty() { 33 | return Err("input file missing")? 34 | } 35 | Ok(buffer) 36 | } 37 | fn open(path: PathBuf) -> Result { 38 | let file = File::open(path)?; 39 | Ok(file) 40 | } 41 | fn write(data: &str, filename: &str) -> Result<(), Error> { 42 | let mut buffer = File::create(filename)?; 43 | buffer.write_all(data.as_bytes())?; 44 | Ok(()) 45 | } 46 | 47 | #[cfg(test)] 48 | mod test { 49 | use std::path::PathBuf; 50 | use super::{load_csv, write_csv}; 51 | #[test] 52 | fn test_valid_load_csv(){ 53 | let filename = PathBuf::from("./input/challenge.csv"); 54 | let csv_data = load_csv(filename); 55 | assert!(csv_data.is_ok()); 56 | } 57 | 58 | #[test] 59 | #[ignore] 60 | fn test_invalid_load_csv(){ 61 | let filename = PathBuf::from("./input/other.csv"); 62 | let csv_data = load_csv(filename); 63 | assert!(csv_data.is_err()); 64 | } 65 | 66 | #[test] 67 | fn test_valid_write_csv(){ 68 | let filename = PathBuf::from("./input/challenge.csv"); 69 | let modified_data = r"a,b,c,d,e\nf,g,h,i,j"; 70 | let output_file = write_csv(&modified_data, "output/test.csv"); 71 | assert!(output_file.is_ok()); 72 | } 73 | } -------------------------------------------------------------------------------- /src/ch10/csv_challenge/src/core/write.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | pub fn replace_column(data: String, column: &str, replacement: &str) 3 | -> Result { 4 | let mut lines = data.lines(); 5 | let headers = lines.next().unwrap(); 6 | let columns: Vec<&str> = headers.split(',').collect(); 7 | let column_number = columns.iter().position(|&e| e == column); 8 | let column_number = match column_number { 9 | Some(column) => column, 10 | None => Err("column name doesn’t exist in the input file")? 11 | }; 12 | let mut result = String::with_capacity(data.capacity()); 13 | result.push_str(&columns.join(",")); 14 | result.push('\n'); 15 | for line in lines { 16 | let mut records: Vec<&str> = line.split(',').collect(); 17 | records[column_number] = replacement; 18 | result.push_str(&records.join(",")); 19 | result.push('\n'); 20 | } 21 | Ok(result) 22 | } 23 | 24 | #[cfg(test)] 25 | mod test { 26 | use std::path::PathBuf; 27 | use super::read::load_csv; 28 | use super::{replace_column}; 29 | 30 | #[test] 31 | fn test_valid_replace_column(){ 32 | let filename = PathBuf::from("./input/challenge.csv"); 33 | let csv_data = load_csv(filename).unwrap(); 34 | let modified_data = replace_column(csv_data, "City", "Beijing"); 35 | assert!(modified_data.is_ok()); 36 | } 37 | 38 | #[test] 39 | fn test_invalid_replace_column(){ 40 | let filename = PathBuf::from("./input/challenge.csv"); 41 | let csv_data = load_csv(filename).unwrap(); 42 | let modified_data = replace_column(csv_data, "City2", "Beijing"); 43 | assert!(modified_data.is_err()); 44 | } 45 | } -------------------------------------------------------------------------------- /src/ch10/csv_challenge/src/err.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | #[derive(Debug)] 3 | pub enum Error { 4 | Io(io::Error), 5 | Program(&'static str), 6 | } 7 | impl From for Error { 8 | fn from(e: io::Error) -> Error { 9 | Error::Io(e) 10 | } 11 | } 12 | impl From<&'static str> for Error { 13 | fn from(e: &'static str) -> Error { 14 | Error::Program(e) 15 | } 16 | } -------------------------------------------------------------------------------- /src/ch10/csv_challenge/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This is documentation for the `csv_challenge` lib crate. 2 | //! 3 | //! Usage: 4 | //! ``` 5 | //! use csv_challenge::{ 6 | //! Opt, 7 | //! {load_csv, write_csv}, 8 | //! replace_column, 9 | //! }; 10 | //! ``` 11 | mod opt; 12 | mod err; 13 | mod core; 14 | // Re-exporting 15 | pub use self::opt::Opt; 16 | pub use self::core::{ 17 | read::{load_csv, write_csv}, 18 | write::replace_column, 19 | }; -------------------------------------------------------------------------------- /src/ch10/csv_challenge/src/main.rs: -------------------------------------------------------------------------------- 1 | use structopt::StructOpt; 2 | use csv_challenge::{ 3 | Opt, 4 | {load_csv, write_csv}, 5 | replace_column, 6 | }; 7 | use std::path::PathBuf; 8 | use std::process; 9 | fn main() { 10 | let opt = Opt::from_args(); 11 | let filename = PathBuf::from(opt.input); 12 | let csv_data = match load_csv(filename) { 13 | Ok(fname) => { fname }, 14 | Err(e) => { 15 | println!("main error: {:?}", e); 16 | process::exit(1); 17 | } 18 | }; 19 | 20 | let modified_data = match 21 | replace_column(csv_data, &opt.column_name, &opt.replacement) 22 | { 23 | Ok(data) => { data }, 24 | Err(e) => { 25 | println!("main error: {:?}", e); 26 | process::exit(1); 27 | } 28 | }; 29 | 30 | let output_file = &opt.output 31 | .unwrap_or("output/output.csv".to_string()); 32 | 33 | match write_csv(&modified_data, &output_file) { 34 | Ok(_) => { 35 | println!("write success!"); 36 | }, 37 | Err(e) => { 38 | println!("main error: {:?}", e); 39 | process::exit(1); 40 | } 41 | } 42 | 43 | 44 | } -------------------------------------------------------------------------------- /src/ch10/csv_challenge/src/opt.rs: -------------------------------------------------------------------------------- 1 | use structopt_derive::*; 2 | 3 | #[derive(StructOpt, Debug)] 4 | #[structopt(name = "csv_challenge", about = "An example of StructOpt usage.")] 5 | pub struct Opt { 6 | /// Needed parameter, the first on the command line. 7 | // #[structopt(short = "v", long = "verbose")] 8 | // pub verbosity: u64, 9 | #[structopt(help = "Input file")] 10 | pub input: String, 11 | #[structopt(help = "Column Name")] 12 | pub column_name: String, 13 | #[structopt(help = "Replacement Column Name")] 14 | pub replacement: String, 15 | #[structopt(help = "Output file, stdout if not present")] 16 | pub output: Option, 17 | } -------------------------------------------------------------------------------- /src/ch10/csv_challenge/tests/integration_test.rs: -------------------------------------------------------------------------------- 1 | // extern crate csv_challenge; 2 | #[cfg(test)] 3 | mod test { 4 | use std::path::PathBuf; 5 | use csv_challenge::{ 6 | Opt, 7 | {load_csv, write_csv}, 8 | replace_column, 9 | }; 10 | #[test] 11 | fn test_csv_challenge(){ 12 | test_load_csv(); 13 | test_replace_column(); 14 | test_write_csv(); 15 | } 16 | fn test_load_csv(){ 17 | let filename = PathBuf::from("./input/challenge.csv"); 18 | let csv_data = load_csv(filename); 19 | assert!(csv_data.is_ok()); 20 | } 21 | fn test_replace_column(){ 22 | let filename = PathBuf::from("./input/challenge.csv"); 23 | let csv_data = load_csv(filename).unwrap(); 24 | let modified_data = replace_column(csv_data, "City", "Beijing"); 25 | assert!(modified_data.is_ok()); 26 | } 27 | 28 | fn test_write_csv(){ 29 | let filename = PathBuf::from("./input/challenge.csv"); 30 | let csv_data = load_csv(filename).unwrap(); 31 | let modified_data = replace_column(csv_data, "City", "Beijing").unwrap(); 32 | let output_file = write_csv(&modified_data, "output/test.csv"); 33 | assert!(output_file.is_ok()); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/ch10/mod.rs: -------------------------------------------------------------------------------- 1 | //! 第十章:模块化开发 2 | //! 3 | 4 | extern crate csv_challenge; 5 | 6 | /// # Examples 7 | /// 8 | /// Basic usage: 9 | /// 10 | /// ``` 11 | /// pub fn title(){ 12 | /// println!("第10章:{}", "模块化开发"); 13 | /// } 14 | /// title(); 15 | /// ``` 16 | pub fn title(){ 17 | println!("第10章:{}", "模块化开发"); 18 | } 19 | 20 | pub mod visibility; -------------------------------------------------------------------------------- /src/ch10/static_hashmap/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /src/ch10/static_hashmap/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "static_hashmap" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | lazy_static = "1.1.0" 9 | 10 | -------------------------------------------------------------------------------- /src/ch10/static_hashmap/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use]extern crate lazy_static; 2 | 3 | mod static_kv { 4 | use std::collections::HashMap; 5 | use std::sync::RwLock; 6 | pub const NF: &'static str = "not found"; 7 | 8 | lazy_static! { 9 | pub static ref MAP: HashMap = { 10 | let mut m = HashMap::new(); 11 | m.insert(0, "foo"); 12 | m 13 | }; 14 | pub static ref MAP_MUT: RwLock> = 15 | { 16 | let mut m = HashMap::new(); 17 | m.insert(0, "bar"); 18 | RwLock::new(m) 19 | }; 20 | } 21 | } 22 | fn read_kv() { 23 | let ref m = static_kv::MAP; 24 | assert_eq!("foo", *m.get(&0).unwrap_or(&static_kv::NF)); 25 | assert_eq!(static_kv::NF, 26 | *m.get(&1).unwrap_or(&static_kv::NF)); 27 | } 28 | fn rw_mut_kv() -> Result<(), String> { 29 | { 30 | let m = static_kv::MAP_MUT 31 | .read().map_err(|e| e.to_string())?; 32 | assert_eq!("bar", *m.get(&0).unwrap_or(&static_kv::NF)); 33 | } 34 | { 35 | let mut m = static_kv::MAP_MUT 36 | .write().map_err(|e| e.to_string())?; 37 | m.insert(1, "baz"); 38 | } 39 | Ok(()) 40 | } 41 | fn main() { 42 | read_kv(); 43 | match rw_mut_kv() { 44 | Ok(()) => { 45 | let m = static_kv::MAP_MUT 46 | .read().map_err(|e| e.to_string()).unwrap(); 47 | assert_eq!("baz", *m.get(&1).unwrap_or(&static_kv::NF)); 48 | }, 49 | Err(e) => {println!("Error {}", e)}, 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/ch10/static_hashmap_2015/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /src/ch10/static_hashmap_2015/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "static_hashmap_2015" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2015" 6 | 7 | [dependencies] 8 | lazy_static = "1.0.0" -------------------------------------------------------------------------------- /src/ch10/static_hashmap_2015/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate lazy_static; 3 | mod static_func; 4 | use static_func::static_kv; 5 | use static_func::read_func::{read_kv, rw_mut_kv}; 6 | 7 | fn main() { 8 | read_kv(); 9 | match rw_mut_kv() { 10 | Ok(()) => { 11 | let m = static_kv::MAP_MUT.read().map_err(|e| e.to_string()).unwrap(); 12 | assert_eq!("baz", *m.get(&1).unwrap_or(&static_kv::NF)); 13 | } 14 | Err(e) => println!("Error {}", e), 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ch10/static_hashmap_2015/src/static_func/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod static_kv; 2 | pub mod read_func; 3 | -------------------------------------------------------------------------------- /src/ch10/static_hashmap_2015/src/static_func/read_func.rs: -------------------------------------------------------------------------------- 1 | use static_func::static_kv; 2 | pub fn read_kv() { 3 | let ref m = static_kv::MAP; 4 | assert_eq!("foo", *m.get(&0).unwrap_or(&static_kv::NF)); 5 | assert_eq!(static_kv::NF, *m.get(&1).unwrap_or(&static_kv::NF)); 6 | } 7 | pub fn rw_mut_kv() -> Result<(), String> { 8 | { 9 | let m = static_kv::MAP_MUT.read().map_err(|e| e.to_string())?; 10 | assert_eq!("bar", *m.get(&0).unwrap_or(&static_kv::NF)); 11 | } 12 | { 13 | let mut m = static_kv::MAP_MUT.write().map_err(|e| e.to_string())?; 14 | m.insert(1, "baz"); 15 | } 16 | Ok(()) 17 | } 18 | -------------------------------------------------------------------------------- /src/ch10/static_hashmap_2015/src/static_func/static_kv.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::sync::RwLock; 3 | pub const NF: &'static str = "not found"; 4 | lazy_static! { 5 | pub static ref MAP: HashMap = { 6 | let mut m = HashMap::new(); 7 | m.insert(0, "foo"); 8 | m 9 | }; 10 | pub static ref MAP_MUT: RwLock> = 11 | { 12 | let mut m = HashMap::new(); 13 | m.insert(0, "bar"); 14 | RwLock::new(m) 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /src/ch10/static_hashmap_2018/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /src/ch10/static_hashmap_2018/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "static_hashmap_2018" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | lazy_static = "1.1.0" -------------------------------------------------------------------------------- /src/ch10/static_hashmap_2018/src/main.rs: -------------------------------------------------------------------------------- 1 | // #![feature(uniform_paths)] 2 | 3 | mod read_func; 4 | use self::read_func::{read_kv, rw_mut_kv}; 5 | 6 | fn main() { 7 | read_kv(); 8 | match rw_mut_kv() { 9 | Ok(()) => { 10 | let m = read_func::static_kv::MAP_MUT.read().map_err(|e| e.to_string()).unwrap(); 11 | assert_eq!("baz", *m.get(&1).unwrap_or(&read_func::static_kv::NF)); 12 | } 13 | Err(e) => println!("Error {}", e), 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/ch10/static_hashmap_2018/src/read_func.rs: -------------------------------------------------------------------------------- 1 | pub mod static_kv; 2 | 3 | pub fn read_kv() { 4 | let ref m = static_kv::MAP; 5 | assert_eq!("foo", *m.get(&0).unwrap_or(&static_kv::NF)); 6 | assert_eq!(static_kv::NF, *m.get(&1).unwrap_or(&static_kv::NF)); 7 | } 8 | pub fn rw_mut_kv() -> Result<(), String> { 9 | { 10 | let m = static_kv::MAP_MUT.read().map_err(|e| e.to_string())?; 11 | assert_eq!("bar", *m.get(&0).unwrap_or(&static_kv::NF)); 12 | } 13 | { 14 | let mut m = static_kv::MAP_MUT.write().map_err(|e| e.to_string())?; 15 | m.insert(1, "baz"); 16 | } 17 | Ok(()) 18 | } -------------------------------------------------------------------------------- /src/ch10/static_hashmap_2018/src/read_func/static_kv.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use std::collections::HashMap; 3 | use std::sync::RwLock; 4 | pub const NF: &'static str = "not found"; 5 | 6 | lazy_static! { 7 | pub static ref MAP: HashMap = { 8 | let mut m = HashMap::new(); 9 | m.insert(0, "foo"); 10 | m 11 | }; 12 | pub static ref MAP_MUT: RwLock> = 13 | { 14 | let mut m = HashMap::new(); 15 | m.insert(0, "bar"); 16 | RwLock::new(m) 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /src/ch10/tt/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /src/ch10/tt/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tt" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /src/ch10/tt/src/bar.rs: -------------------------------------------------------------------------------- 1 | use crate::foo; 2 | 3 | pub fn hello(){ 4 | foo::hello::hello(); 5 | } -------------------------------------------------------------------------------- /src/ch10/tt/src/foo.rs: -------------------------------------------------------------------------------- 1 | pub mod hello; -------------------------------------------------------------------------------- /src/ch10/tt/src/foo/hello.rs: -------------------------------------------------------------------------------- 1 | pub fn hello(){ 2 | println!("hello"); 3 | } -------------------------------------------------------------------------------- /src/ch10/tt/src/main.rs: -------------------------------------------------------------------------------- 1 | mod foo; 2 | mod bar; 3 | 4 | fn main() { 5 | // bar::hello(); 6 | println!("hello"); 7 | } 8 | -------------------------------------------------------------------------------- /src/ch10/use_regex/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /src/ch10/use_regex/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "use_regex" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | regex = "1.0.5" 9 | lazy_static = "1.1.0" 10 | -------------------------------------------------------------------------------- /src/ch10/use_regex/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate lazy_static; 2 | extern crate regex; 3 | use regex::Regex; 4 | 5 | lazy_static! { 6 | static ref RE: Regex = Regex::new(r"(?x) 7 | (?P\d{4})- # the year 8 | (?P\d{2})- # the month 9 | (?P\d{2}) # the day 10 | ").unwrap(); 11 | static ref EMAIL_RE: Regex = Regex::new(r"(?x) 12 | ^\w+@(?:gmail|163|qq)\.(?:com|cn|com\.cn|net)$ 13 | ").unwrap(); 14 | } 15 | 16 | fn regex_date(text: &str) -> regex::Captures { 17 | RE.captures(text).unwrap() 18 | } 19 | 20 | fn regex_email(text: &str) -> bool { 21 | EMAIL_RE.is_match(text) 22 | } 23 | 24 | fn main() { 25 | let caps = regex_date("2018-01-01"); 26 | assert_eq!("2018", &caps["year"]); 27 | assert_eq!("01", &caps["month"]); 28 | assert_eq!("01", &caps["day"]); 29 | let after = RE.replace_all("2018-01-01", "$month/$day/$year"); 30 | assert_eq!(after, "01/01/2018"); 31 | assert!(regex_email("alex@gmail.com"), true); 32 | assert_eq!(regex_email("alex@gmail.cn.com"), false); 33 | } -------------------------------------------------------------------------------- /src/ch10/visibility.rs: -------------------------------------------------------------------------------- 1 | /// # 模块 2 | /// 3 | /// 本章相关包: 4 | /// 5 | /// - static_hashmap 6 | /// - static_hashmap_2015 7 | /// - static_hashmap_2018 8 | /// - csv_challenge 9 | /// 10 | /// 请参考本书随书GitHub仓库相关源码 11 | /// 12 | /// Basic usage: 模块可见性 Rust 2015 Edtion 13 | /// 14 | /// ``` 15 | /// pub mod outer_mod { 16 | /// pub(self) fn outer_mod_fn() {} 17 | /// pub mod inner_mod { 18 | /// // use outer_mod::outer_mod_fn; 19 | /// // 对外层模块 `outer_mod` 可见 20 | /// pub(in outer_mod) fn outer_mod_visible_fn() {} 21 | /// // 对整个crate可见 22 | /// pub(crate) fn crate_visible_fn() {} 23 | /// // `outer_mod` 内部可见 24 | /// pub(super) fn super_mod_visible_fn() { 25 | /// // 访问同一模块的函数 26 | /// inner_mod_visible_fn(); 27 | /// // 访问父模块的函数需要使用“::”前缀 28 | /// ::outer_mod::outer_mod_fn(); 29 | /// } 30 | /// // 仅在`inner_mod`可见 31 | /// pub(self) fn inner_mod_visible_fn() {} 32 | /// } 33 | /// 34 | /// pub fn foo() { 35 | /// inner_mod::outer_mod_visible_fn(); 36 | /// inner_mod::crate_visible_fn(); 37 | /// inner_mod::super_mod_visible_fn(); 38 | /// 39 | /// // 不能使用inner_mod 的私有函数 40 | /// // inner_mod::inner_mod_visible_fn(); 41 | /// } 42 | /// } 43 | /// fn bar() { 44 | /// // 该函数对整个crate可见 45 | /// outer_mod::inner_mod::crate_visible_fn(); 46 | /// 47 | /// // 该函数只对outer_mod可见 48 | /// // outer_mod::inner_mod::super_mod_visible_fn(); 49 | /// 50 | /// // 该函数只对outer_mod可见 51 | /// // outer_mod::inner_mod::outer_mod_visible_fn(); 52 | /// 53 | /// // 通过foo函数调用内部细节 54 | /// outer_mod::foo(); 55 | /// } 56 | /// fn main() { bar() } 57 | /// ``` 58 | /// 59 | /// 60 | /// Basic usage: 模块可见性 Rust 2018 Edtion 61 | /// 62 | /// 请在Play手动选择Rust edition运行 63 | /// 64 | /// ``` 65 | /// pub mod outer_mod { 66 | /// pub(self) fn outer_mod_fn() {} 67 | /// 68 | /// pub mod inner_mod { 69 | /// // 在Rust 2018 edtion 模块系统必须使用use导入 70 | /// use crate::outer_mod::outer_mod_fn; 71 | /// // 对外层模块 `outer_mod` 可见 72 | /// pub(in crate::outer_mod) fn outer_mod_visible_fn() {} 73 | /// // 对整个crate可见 74 | /// pub(crate) fn crate_visible_fn() {} 75 | /// // `outer_mod` 内部可见 76 | /// pub(super) fn super_mod_visible_fn() { 77 | /// // 访问同一模块的函数 78 | /// inner_mod_visible_fn(); 79 | /// // 使用use导入了outer_mod 80 | /// outer_mod_fn(); 81 | /// } 82 | /// // 仅在`inner_mod`可见 83 | /// pub(self) fn inner_mod_visible_fn() {} 84 | /// } 85 | /// 86 | /// pub fn foo() { 87 | /// inner_mod::outer_mod_visible_fn(); 88 | /// inner_mod::crate_visible_fn(); 89 | /// inner_mod::super_mod_visible_fn(); 90 | /// 91 | /// // 不能使用inner_mod 的私有函数 92 | /// // inner_mod::inner_mod_visible_fn(); 93 | /// } 94 | /// } 95 | /// fn bar() { 96 | /// // 该函数对整个crate可见 97 | /// outer_mod::inner_mod::crate_visible_fn(); 98 | /// 99 | /// // 该函数只对outer_mod可见 100 | /// // outer_mod::inner_mod::super_mod_visible_fn(); 101 | /// 102 | /// // 该函数只对outer_mod可见 103 | /// // outer_mod::inner_mod::outer_mod_visible_fn(); 104 | /// 105 | /// // 通过foo函数调用内部细节 106 | /// outer_mod::foo(); 107 | /// } 108 | /// fn main() { bar() } 109 | /// ``` 110 | pub fn visibility(){ 111 | unimplemented!(); 112 | } -------------------------------------------------------------------------------- /src/ch11/atomics.rs: -------------------------------------------------------------------------------- 1 | /// # 原子类型 2 | /// 3 | /// Basic usage: 使用原子类型实现自旋锁 4 | /// 5 | /// ```rust 6 | /// use std::sync::Arc; 7 | /// use std::sync::atomic::{AtomicUsize, Ordering}; 8 | /// use std::thread; 9 | /// fn main() { 10 | /// let spinlock = Arc::new(AtomicUsize::new(1)); 11 | /// let spinlock_clone = spinlock.clone(); 12 | /// let thread = thread::spawn(move|| { 13 | /// spinlock_clone.store(0, Ordering::SeqCst); 14 | /// }); 15 | /// while spinlock.load(Ordering::SeqCst) != 0 {} 16 | /// if let Err(panic) = thread.join() { 17 | /// println!("Thread had an error: {:?}", panic); 18 | /// } 19 | /// } 20 | /// ``` 21 | pub fn atomic_demo(){ 22 | unimplemented!(); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/ch11/channels.rs: -------------------------------------------------------------------------------- 1 | /// # CSP并发模型 2 | /// 3 | /// 查看随书源码中的pow库,可以查看channel实现工作量证明的示例 4 | /// 5 | /// Basic usage: 流通道channel示例 6 | /// 7 | /// 异步channel 8 | /// 9 | /// ```rust 10 | /// use std::thread; 11 | /// use std::sync::mpsc::channel; 12 | /// fn main() { 13 | /// let (tx, rx) = channel(); 14 | /// thread::spawn(move|| { 15 | /// tx.send(10).unwrap(); 16 | /// }); 17 | /// assert_eq!(rx.recv().unwrap(), 10); 18 | /// } 19 | /// ``` 20 | /// 21 | /// Basic usage: 多生产者(共享通道) 22 | /// 23 | /// 异步channel 24 | /// 25 | /// ```rust 26 | /// use std::thread; 27 | /// use std::sync::mpsc::channel; 28 | /// fn main() { 29 | /// let (tx, rx) = channel(); 30 | /// for i in 0..10 { 31 | /// let tx = tx.clone(); 32 | /// thread::spawn(move|| { 33 | /// tx.send(i).unwrap(); 34 | /// }); 35 | /// } 36 | /// for _ in 0..10 { 37 | /// let j = rx.recv().unwrap(); 38 | /// assert!(0 <= j && j < 10); 39 | /// } 40 | /// } 41 | /// ``` 42 | /// 43 | /// Basic usage: 同步通道 44 | /// 45 | /// 46 | /// ```rust 47 | /// use std::sync::mpsc::sync_channel; 48 | /// use std::thread; 49 | /// fn main() { 50 | /// let (tx, rx) = sync_channel(1); 51 | /// tx.send(1).unwrap(); 52 | /// thread::spawn(move|| { 53 | /// tx.send(2).unwrap(); 54 | /// }); 55 | /// assert_eq!(rx.recv().unwrap(), 1); 56 | /// assert_eq!(rx.recv().unwrap(), 2); 57 | /// } 58 | /// ``` 59 | /// 60 | /// Basic usage: Channel死锁 61 | /// 62 | /// 共享通道 63 | /// 64 | /// ```rust 65 | /// use std::thread; 66 | /// use std::sync::mpsc::channel; 67 | /// fn main() { 68 | /// let (tx, rx) = channel(); 69 | /// for i in 0..5 { 70 | /// let tx = tx.clone(); 71 | /// thread::spawn(move || { 72 | /// tx.send(i).unwrap(); 73 | /// }); 74 | /// } 75 | /// // drop(tx); // 使用drop解决死锁 76 | /// for j in rx.iter() { 77 | /// println!("{:?}", j); 78 | /// } 79 | /// } 80 | /// ``` 81 | /// 82 | /// Basic usage: Channel没有死锁 83 | /// 84 | /// 流通道 85 | /// 86 | /// ```rust 87 | /// use std::sync::mpsc::channel; 88 | /// use std::thread; 89 | /// fn main() { 90 | /// let (tx, rx) = channel(); 91 | /// thread::spawn(move || { 92 | /// tx.send(1u8).unwrap(); 93 | /// tx.send(2u8).unwrap(); 94 | /// tx.send(3u8).unwrap(); 95 | /// }); 96 | /// for x in rx.iter() { 97 | /// println!("receive: {}", x); 98 | /// } 99 | /// } 100 | /// ``` 101 | pub fn channel_demo(){ 102 | unimplemented!(); 103 | } 104 | -------------------------------------------------------------------------------- /src/ch11/crossbeam.rs: -------------------------------------------------------------------------------- 1 | /// # Crossbeam使用 2 | /// 3 | /// Basic usage: 使用标准库,出错 4 | /// 5 | /// ```rust 6 | /// let array = [1, 2, 3]; 7 | /// let mut guards = vec![]; 8 | /// 9 | /// // 这样也可以 for &i in &array { 10 | /// for i in &array { 11 | /// let guard = std::thread::spawn(move || { 12 | /// println!("element: {}", i); 13 | /// }); 14 | /// 15 | /// guards.push(guard); 16 | /// } 17 | /// 18 | /// for guard in guards { 19 | /// guard.join().unwrap(); 20 | /// } 21 | /// ``` 22 | /// 23 | /// Basic usage: 使用Arc修正 24 | /// 25 | /// ```rust 26 | /// use std::sync::Arc; 27 | /// 28 | /// let array = Arc::new([1, 2, 3]); 29 | /// let mut guards = vec![]; 30 | /// 31 | /// for i in 0..array.len() { 32 | /// let a = array.clone(); 33 | /// 34 | /// let guard = std::thread::spawn(move || { 35 | /// println!("element: {}", a[i]); 36 | /// }); 37 | /// 38 | /// guards.push(guard); 39 | /// } 40 | /// 41 | /// for guard in guards { 42 | /// guard.join().unwrap(); 43 | /// } 44 | /// ``` 45 | /// 46 | /// Basic usage: 使用crossbeam的scoped thread 47 | /// 48 | /// 请用 Rust 2018 Edtion 49 | /// 50 | /// ```rust 51 | /// use crossbeam::thread::scope; 52 | /// 53 | /// let array = [1, 2, 3]; 54 | /// 55 | /// scope(|scope| { 56 | /// for i in &array { 57 | /// scope.spawn(move || { 58 | /// println!("element: {}", i); 59 | /// }); 60 | /// } 61 | /// }); 62 | /// ``` 63 | /// Basic usage: 使用crossbeam channel 「0.7.1」 64 | /// 65 | /// select!宏语法变更 66 | /// 67 | /// 请用 Rust 2018 Edtion 68 | /// 69 | /// ```rust 70 | /// use crossbeam_channel::select; 71 | /// use crossbeam_channel as channel; 72 | /// 73 | /// use std::thread; 74 | /// 75 | /// fn fibonacci(fib: channel::Sender, quit: channel::Receiver<()>) { 76 | /// let (mut x, mut y) = (0, 1); 77 | /// loop { 78 | /// select! { 79 | /// send(fib, x) -> _ => { 80 | /// let tmp = x; 81 | /// x = y; 82 | /// y = tmp + y; 83 | /// } 84 | /// recv(quit) -> _ => { 85 | /// println!("quit"); 86 | /// return; 87 | /// } 88 | /// } 89 | /// } 90 | /// } 91 | /// 92 | /// fn main() { 93 | /// let (fib_s, fib_r) = channel::bounded(0); 94 | /// let (quit_s, quit_r) = channel::bounded(0); 95 | /// 96 | /// thread::spawn(move || { 97 | /// for _ in 0..10 { 98 | /// println!("{}", fib_r.recv().unwrap()); 99 | /// } 100 | /// quit_s.send(()); 101 | /// }); 102 | /// 103 | /// fibonacci(fib_s, quit_r); 104 | /// } 105 | /// ``` 106 | /// 107 | /// 108 | /// Basic usage: 使用crossbeam channel 「已过期」 109 | /// 110 | /// 请用 Rust 2018 Edtion 111 | /// 112 | /// ```rust 113 | /// use crossbeam_channel::select; 114 | /// use crossbeam_channel as channel; 115 | /// 116 | /// use std::thread; 117 | /// 118 | /// fn fibonacci(fib: channel::Sender, quit: channel::Receiver<()>) { 119 | /// let (mut x, mut y) = (0, 1); 120 | /// loop { 121 | /// select! { 122 | /// send(fib, x) => { 123 | /// let tmp = x; 124 | /// x = y; 125 | /// y = tmp + y; 126 | /// } 127 | /// recv(quit) => { 128 | /// println!("quit"); 129 | /// return; 130 | /// } 131 | /// } 132 | /// } 133 | /// } 134 | /// 135 | /// fn main() { 136 | /// let (fib_s, fib_r) = channel::bounded(0); 137 | /// let (quit_s, quit_r) = channel::bounded(0); 138 | /// 139 | /// thread::spawn(move || { 140 | /// for _ in 0..10 { 141 | /// println!("{}", fib_r.recv().unwrap()); 142 | /// } 143 | /// quit_s.send(()); 144 | /// }); 145 | /// 146 | /// fibonacci(fib_s, quit_r); 147 | /// } 148 | /// ``` 149 | /// 150 | /// Basic usage: 使用crossbeam channel,通过引用共享 151 | /// 152 | /// 请用 Rust 2018 Edtion 153 | /// 154 | /// ```rust 155 | /// use crossbeam::channel as channel; 156 | /// fn main(){ 157 | /// let (s, r) = channel::unbounded(); 158 | /// 159 | /// crossbeam::scope(|scope| { 160 | /// // Spawn a thread that sends one message and then receives one. 161 | /// scope.spawn(|| { 162 | /// s.send(1); 163 | /// r.recv().unwrap(); 164 | /// }); 165 | /// 166 | /// // Spawn another thread that does the same thing. 167 | /// scope.spawn(|| { 168 | /// s.send(2); 169 | /// r.recv().unwrap(); 170 | /// }); 171 | /// }); 172 | /// } 173 | /// ``` 174 | /// 175 | /// Basic usage: 使用crossbeam channel,通过clone共享 176 | /// 177 | /// 请用 Rust 2018 Edtion 178 | /// 179 | /// ```rust 180 | /// use std::thread; 181 | /// use crossbeam::channel as channel; 182 | /// 183 | /// fn main(){ 184 | /// let (s1, r1) = channel::unbounded(); 185 | /// let (s2, r2) = (s1.clone(), r1.clone()); 186 | /// 187 | /// // Spawn a thread that sends one message and then receives one. 188 | /// thread::spawn(move || { 189 | /// s1.send(1); 190 | /// r1.recv().unwrap(); 191 | /// }); 192 | /// 193 | /// // Spawn another thread that receives a message and then sends one. 194 | /// thread::spawn(move || { 195 | /// r2.recv().unwrap(); 196 | /// s2.send(2); 197 | /// }); 198 | /// } 199 | /// ``` 200 | pub fn crossbeam_demo() { 201 | unimplemented!(); 202 | } 203 | -------------------------------------------------------------------------------- /src/ch11/futures-demo/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /src/ch11/futures-demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "futures-demo" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | futures-preview = "0.3.0-alpha.9" 9 | -------------------------------------------------------------------------------- /src/ch11/futures-demo/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(arbitrary_self_types, futures_api, async_await, await_macro, pin)] 2 | 3 | // use futures::{ 4 | // executor::{ThreadPool,LocalPool}, 5 | // task::{SpawnExt, LocalSpawnExt}, 6 | // }; 7 | use futures::{ 8 | executor::ThreadPool, 9 | task::SpawnExt, 10 | }; 11 | use std::future::{Future}; 12 | use std::pin::Pin; 13 | use std::task::*; 14 | // use std::thread; 15 | // use std::time::Duration; 16 | 17 | pub struct AlmostReady { 18 | ready: bool, 19 | value: i32, 20 | } 21 | 22 | pub fn almost_ready(value: i32) -> AlmostReady { 23 | AlmostReady { ready: false, value } 24 | } 25 | 26 | impl Future for AlmostReady { 27 | type Output = i32; 28 | fn poll(self: Pin<&mut Self>, lw: &LocalWaker) 29 | -> Poll 30 | { 31 | if self.ready { 32 | Poll::Ready(self.value + 1) 33 | } else { 34 | unsafe { Pin::get_mut_unchecked(self).ready = true ;} 35 | lw.wake(); 36 | Poll::Pending 37 | } 38 | } 39 | } 40 | 41 | fn main() { 42 | let mut executor = ThreadPool::new().unwrap(); 43 | let future = async { 44 | println!("howdy!"); 45 | let x = await!(almost_ready(5)); 46 | println!("done: {:?}", x); 47 | }; 48 | // executor.spawn(future).unwrap(); 49 | // let five_seconds = Duration::new(1, 0); 50 | // thread::sleep(five_seconds); 51 | 52 | executor.run(future); 53 | 54 | // // LocalPool run 55 | // let mut executor = LocalPool::new(); 56 | // // let mut spawner = executor.spawner(); 57 | // let future = async { 58 | // println!("howdy!"); 59 | // let x = await!(almost_ready(5)); 60 | // println!("done: {:?}", x); 61 | // }; 62 | 63 | // // spawner.spawn_local(future).unwrap(); 64 | // executor.run_until(future); 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/ch11/mod.rs: -------------------------------------------------------------------------------- 1 | //! 第十一章:安全并发 2 | //! 3 | 4 | /// # Examples 5 | /// 6 | /// Basic usage: 7 | /// 8 | /// ``` 9 | /// pub fn title(){ 10 | /// println!("第11章:{}", "安全并发"); 11 | /// } 12 | /// title(); 13 | /// ``` 14 | pub fn title(){ 15 | println!("第11章:{}", "安全并发"); 16 | } 17 | 18 | pub mod thread_unsafe; 19 | pub mod thread_management; 20 | pub mod thread_sync; 21 | pub mod atomics; 22 | pub mod channels; 23 | pub mod rayon; 24 | pub mod crossbeam; 25 | pub mod generator; 26 | -------------------------------------------------------------------------------- /src/ch11/pow/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /src/ch11/pow/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pow" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | itertools = "0.7.8" 9 | sha256 = "1" 10 | -------------------------------------------------------------------------------- /src/ch11/pow/src/main.rs: -------------------------------------------------------------------------------- 1 | 2 | use itertools::Itertools; 3 | use sha256::digest; 4 | 5 | 6 | use std::{ 7 | thread, 8 | sync::{mpsc, Arc}, 9 | sync::atomic::{AtomicBool, Ordering}, 10 | }; 11 | 12 | const BASE: usize = 42; 13 | const THREADS: usize = 8; 14 | static DIFFICULTY: &'static str = "00000"; 15 | struct Solution(usize, String); 16 | 17 | fn verify(number: usize) -> Option { 18 | let hash = digest((number * BASE).to_string()); 19 | if hash.starts_with(DIFFICULTY) { 20 | Some(Solution(number, hash)) 21 | } else { None } 22 | } 23 | 24 | fn find( 25 | start_at: usize, 26 | sender: mpsc::Sender, 27 | is_solution_found: Arc 28 | ) { 29 | for number in (start_at..).step_by(THREADS) { 30 | if is_solution_found.load(Ordering::Relaxed) { return; } 31 | if let Some(solution) = verify(number) { 32 | is_solution_found.store(true, Ordering::Relaxed); 33 | sender.send(solution).unwrap(); 34 | return; 35 | } 36 | } 37 | } 38 | 39 | fn main() { 40 | println!("PoW : Find a number, 41 | SHA256(the number * {}) == \"{}......\" ", BASE, DIFFICULTY); 42 | println!("Started {} threads", THREADS); 43 | println!("Please wait... "); 44 | let is_solution_found = Arc::new(AtomicBool::new(false)); 45 | let (sender, receiver) = mpsc::channel(); 46 | for i in 0..THREADS { 47 | let sender_n = sender.clone(); 48 | let is_solution_found = is_solution_found.clone(); 49 | thread::spawn(move || { 50 | find(i, sender_n, is_solution_found); 51 | }); 52 | } 53 | match receiver.recv() { 54 | Ok(Solution(i, hash)) => { 55 | println!("Found the solution: "); 56 | println!("The number is: {}, 57 | and hash result is : {}.", i, hash); 58 | }, 59 | Err(_) => panic!("Worker threads disconnected!"), 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/ch11/rayon.rs: -------------------------------------------------------------------------------- 1 | 2 | /// # Rayon并行迭代器 3 | /// 4 | /// Basic usage: 并行迭代器 5 | /// 6 | /// ```rust 7 | /// extern crate rayon; 8 | /// use rayon::prelude::*; 9 | /// fn sum_of_squares(input: &[i32]) -> i32 { 10 | /// input.par_iter().map(|&i| i * i).sum() 11 | /// } 12 | /// fn increment_all(input: &mut [i32]) { 13 | /// input.par_iter_mut().for_each(|p| *p += 1); 14 | /// } 15 | /// fn main(){ 16 | /// let v = [1,2,3,4,5,6,7,8,9,10]; 17 | /// let r = sum_of_squares(&v); 18 | /// println!("{}", r); 19 | /// let mut v = [1,2,3,4,5,6,7,8,9,10]; 20 | /// increment_all(&mut v); 21 | /// println!("{:?}", v); 22 | /// } 23 | /// ``` 24 | /// 25 | /// Basic usage: 使用Rayon提供的join 26 | /// 27 | /// ```rust 28 | /// extern crate rayon; 29 | /// fn fib(n: u32) -> u32 { 30 | /// if n < 2 { return n; } 31 | /// let (a, b) = rayon::join( 32 | /// || fib(n - 1), || fib(n - 2) 33 | /// ); 34 | /// a + b 35 | /// } 36 | /// fn main() { 37 | /// let r = fib(32); 38 | /// assert_eq!(r, 2178309); 39 | /// } 40 | /// ``` 41 | pub fn rayon(){ 42 | unimplemented!(); 43 | } 44 | 45 | /// # 协程 46 | /// 47 | /// Basic usage: 生成器 48 | /// 49 | /// ```rust 50 | /// #![feature(generators, generator_trait)] 51 | /// use std::ops::{Generator, GeneratorState}; 52 | /// fn main() { 53 | /// let mut generator = || { 54 | /// println!("start"); 55 | /// yield 1; 56 | /// println!("back"); 57 | /// return "foo" 58 | /// }; 59 | /// match generator.resume() { 60 | /// GeneratorState::Yielded(1) => {println!("yield 1");} 61 | /// _ => panic!("unexpected value from resume"), 62 | /// } 63 | /// match generator.resume() { 64 | /// GeneratorState::Complete("foo") => {println!("return foo")} 65 | /// _ => panic!("unexpected value from resume"), 66 | /// } 67 | /// } 68 | /// ``` 69 | pub fn generator(){ 70 | unimplemented!(); 71 | } -------------------------------------------------------------------------------- /src/ch11/simd-demo/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /src/ch11/simd-demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "simd-demo" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | jetscii = "0.4.3" 9 | stdsimd = "0.1.0" 10 | 11 | 12 | [[bin]] 13 | path = "src/auto_vector.rs" 14 | name = "auto_vector" 15 | 16 | [[bin]] 17 | path = "src/main.rs" 18 | name = "main" -------------------------------------------------------------------------------- /src/ch11/simd-demo/README.md: -------------------------------------------------------------------------------- 1 | # 说明 2 | 3 | ``` 4 | $ cargo run --bin auto_vector 5 | $ cargo run --bin main 6 | ``` -------------------------------------------------------------------------------- /src/ch11/simd-demo/src/auto_vector.rs: -------------------------------------------------------------------------------- 1 | // cargo run --bin auto_vector 2 | fn add_quickly_fallback(a: &[u8], b: &[u8], c: &mut [u8]) { 3 | for ((a, b), c) in a.iter().zip(b).zip(c) { 4 | *c = *a + *b; 5 | } 6 | } 7 | 8 | // LLVM为指定的平台自动向量化为AVX2,生成优化的向量化代码 9 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 10 | #[target_feature(enable = "avx2")] 11 | unsafe fn add_quickly_avx2(a: &[u8], b: &[u8], c: &mut [u8]) { 12 | add_quickly_fallback(a, b, c) 13 | } 14 | 15 | // LLVM为指定的平台自动向量化为AVX2,生成优化的向量化代码 16 | fn add_quickly(a: &[u8], b: &[u8], c: &mut [u8]) { 17 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 18 | { 19 | if is_x86_feature_detected!("avx2") { 20 | println!("support avx2"); 21 | return unsafe { add_quickly_avx2(a, b, c) } 22 | } 23 | } 24 | add_quickly_fallback(a, b, c) 25 | } 26 | 27 | fn main() { 28 | // 使用LLVM自动向量化 29 | let mut dst = [0, 2]; 30 | add_quickly(&[1, 2], &[2, 3], &mut dst); 31 | assert_eq!(dst, [3, 5]); 32 | } -------------------------------------------------------------------------------- /src/ch11/simd-demo/src/faster_main.rs: -------------------------------------------------------------------------------- 1 | // #![feature(stdsimd)] 2 | // use faster::*; 3 | 4 | 5 | 6 | // fn main() { 7 | // // let lots_of_84s = (&[-10i8; 33][..]).simd_iter(i8s(0)) 8 | // // .simd_map(|v| i8s(9) * v.abs().be_i8s() - i8s(4) - i8s(2)) 9 | // // .simd_map(|v| v) 10 | // // .scalar_collect(); 11 | 12 | // // let lots_of_3s = (&[-123.456f32; 128][..]).simd_iter(f32s(0.0)) 13 | // // .simd_map(|v| { f32s(9.0) * v.abs().sqrt().rsqrt().ceil().sqrt() - 14 | // // f32s(4.0) - f32s(2.0) }) 15 | // // .scalar_collect(); 16 | 17 | // // let lots_of_3s_sc = (&[-123.456f32; 128][..]).iter() 18 | // // .map(|v| { 9.0 * v.abs().sqrt().sqrt().recip().ceil().sqrt() - 19 | // // 4.0 - 2.0 }) 20 | // // .collect::>(); 21 | 22 | // // let mut some_u8s = [0u8; 100]; 23 | // // let filled_u8s = (&[5u8; 100][..]).simd_iter(u8s(0)) 24 | // // .simd_map(|vector| vector * u8s(2)) 25 | // // .scalar_fill(&mut some_u8s); 26 | 27 | // // let reduced = (&[-1.0f32; 128][..]).simd_iter(f32s(0.0)) 28 | // // .simd_reduce(f32s(0.0), |a, v| a + v.abs().sqrt().sqrt().floor()).sum(); 29 | 30 | // // let strided = (0..20u32).collect::>().as_slice() 31 | // // .stride_two(tuplify!(2, u32s(99))).zip().simd_map(|(a, b)| a + b) 32 | // // .scalar_collect(); 33 | 34 | // // println!("{:?}\n{:?}\n{:?}\n{:?}\n{:?}\n{:?}\n{:?}\n", lots_of_84s, lots_of_3s, lots_of_3s_sc, filled_u8s, filled_u8s.len(), reduced, strided); 35 | // } 36 | 37 | -------------------------------------------------------------------------------- /src/ch11/simd-demo/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(stdsimd)] 2 | 3 | // use jetscii::{ascii_chars, bytes, Substring}; 4 | 5 | use ::std as real_std; 6 | use stdsimd as std; 7 | #[cfg(target_arch = "x86")] 8 | use ::std::arch::x86::*; 9 | #[cfg(target_arch = "x86_64")] 10 | use ::std::arch::x86_64::*; 11 | 12 | // LLVM为指定的平台自动向量化为AVX2,生成优化的向量化代码 13 | fn add_quickly(a: &[u8], b: &[u8], c: &mut [u8]) { 14 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 15 | { 16 | if is_x86_feature_detected!("avx2") { 17 | return unsafe { add_quickly_avx2(a, b, c) } 18 | } 19 | } 20 | add_quickly_fallback(a, b, c) 21 | } 22 | // LLVM为指定的平台自动向量化为AVX2,生成优化的向量化代码 23 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 24 | #[target_feature(enable = "avx2")] 25 | unsafe fn add_quickly_avx2(a: &[u8], b: &[u8], c: &mut [u8]) { 26 | add_quickly_fallback(a, b, c) 27 | } 28 | 29 | fn add_quickly_fallback(a: &[u8], b: &[u8], c: &mut [u8]) { 30 | for ((a, b), c) in a.iter().zip(b).zip(c) { 31 | *c = *a + *b; 32 | } 33 | } 34 | 35 | fn main() { 36 | // let part_number = "8-67-J5-2:rev:1"; 37 | // let first = ascii_chars!(':', '-').find(part_number); 38 | // assert_eq!(first, Some(1)); 39 | 40 | // let raw_data = [0x00, 0x01, 0x10, 0xFF, 0x42]; 41 | // let first = bytes!(0x01, 0x10).find(&raw_data); 42 | // assert_eq!(first, Some(1)); 43 | 44 | // let colors = "red, blue, green"; 45 | // let first = Substring::new(", ").find(colors); 46 | // assert_eq!(first, Some(3)); 47 | 48 | // #[cfg(feature = "pattern")] { 49 | // let colors = "red, blue, green"; 50 | // let colors: Vec<_> = colors.split(Substring::new(", ")).collect(); 51 | // assert_eq!(&colors, &["red", "blue", "green"]); 52 | // } 53 | 54 | if is_x86_feature_detected!("sse4.2") { 55 | #[target_feature(enable = "sse4.2")] 56 | unsafe fn worker() { 57 | // The string we want to search for with some 58 | // extra bytes we do not want to search for. 59 | let needle = b"\r\n\t ignore this "; 60 | 61 | // The string we want to find a substring in 62 | let haystack = b"Split a \r\n\t line "; 63 | 64 | let a = _mm_loadu_si128(needle.as_ptr() as *const _); 65 | let b = _mm_loadu_si128(haystack.as_ptr() as *const _); 66 | 67 | // Note: We explicitly specify we only want to search `b` for the 68 | // first 3 characters of a. 69 | let idx = _mm_cmpestri(a, 3, b, 20, _SIDD_CMP_EQUAL_ORDERED); 70 | 71 | assert_eq!(idx, 8); 72 | } 73 | unsafe { worker(); } 74 | } 75 | // 使用LLVM自动向量化 76 | let mut dst = [0]; 77 | add_quickly(&[1], &[2], &mut dst); 78 | assert_eq!(dst[0], 3); 79 | } 80 | -------------------------------------------------------------------------------- /src/ch11/thread_management.rs: -------------------------------------------------------------------------------- 1 | /// # 线程管理 2 | /// 3 | /// Basic usage: 创建线程 4 | /// 5 | /// ``` 6 | /// use std::thread; 7 | /// fn main() { 8 | /// let mut v = vec![]; 9 | /// for id in 0..5 { 10 | /// let child = thread::spawn(move || { 11 | /// println!("in child: {}", id); 12 | /// }); 13 | /// v.push(child); 14 | /// } 15 | /// println!("in main : join before "); 16 | /// for child in v { 17 | /// child.join(); 18 | /// } 19 | /// println!("in main : join after"); 20 | /// } 21 | /// ``` 22 | /// 23 | /// Basic usage: 定制线程栈的大小 24 | /// 25 | /// spawn生成的线程默认栈大小是2MiB 26 | /// 27 | /// ```rust 28 | /// use std::panic; 29 | /// use std::thread::{Builder, current}; 30 | /// fn main() { 31 | /// let mut v = vec![]; 32 | /// for id in 0..5 { 33 | /// let thread_name = format!("child-{}", id); 34 | /// let size: usize = 3 * 1024; 35 | /// let builder = Builder::new() 36 | /// .name(thread_name).stack_size(size); 37 | /// let child = builder.spawn(move || { 38 | /// println!("in child: {}", id); 39 | /// if id == 3 { 40 | /// panic::catch_unwind(|| { 41 | /// panic!("oh no!"); 42 | /// }); 43 | /// println!("in {} do sm", current().name().unwrap()); 44 | /// } 45 | /// }).unwrap(); 46 | /// v.push(child); 47 | /// } 48 | /// for child in v { 49 | /// child.join().unwrap(); 50 | /// } 51 | /// } 52 | /// ``` 53 | /// 54 | /// 55 | /// Basic usage: 线程本地存储 TLS 56 | /// 57 | /// 58 | /// ```rust 59 | /// use std::cell::RefCell; 60 | /// use std::thread; 61 | /// fn main() { 62 | /// thread_local!(static FOO: RefCell = RefCell::new(1)); 63 | /// FOO.with(|f| { 64 | /// assert_eq!(*f.borrow(), 1); 65 | /// *f.borrow_mut() = 2; 66 | /// }); 67 | /// thread::spawn(|| { 68 | /// FOO.with(|f| { 69 | /// assert_eq!(*f.borrow(), 1); 70 | /// *f.borrow_mut() = 3; 71 | /// }); 72 | /// }); 73 | /// FOO.with(|f| { 74 | /// assert_eq!(*f.borrow(), 2); 75 | /// }); 76 | /// } 77 | /// ``` 78 | /// 79 | /// 80 | /// Basic usage: park和unpark同步原语示例 81 | /// 82 | /// 83 | /// ```rust 84 | /// use std::thread; 85 | /// use std::time::Duration; 86 | /// fn main() { 87 | /// let parked_thread = thread::Builder::new() 88 | /// .spawn(|| { 89 | /// println!("Parking thread"); 90 | /// thread::park(); 91 | /// println!("Thread unparked"); 92 | /// }).unwrap(); 93 | /// thread::sleep(Duration::from_millis(10)); 94 | /// println!("Unpark the thread"); 95 | /// parked_thread.thread().unpark(); 96 | /// parked_thread.join().unwrap(); 97 | /// } 98 | /// ``` 99 | pub fn thread_management(){ 100 | unimplemented!(); 101 | } -------------------------------------------------------------------------------- /src/ch11/thread_pool/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /src/ch11/thread_pool/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "thread_pool" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | num_cpus = "1.8" 9 | -------------------------------------------------------------------------------- /src/ch11/thread_unsafe.rs: -------------------------------------------------------------------------------- 1 | /// # 竞态条件与临界区 2 | /// 3 | /// Basic usage: 一段线程不安全的代码 4 | /// 5 | /// 但实际执行多次会看到不同的输出结果,基本会出现以下两种情况: 6 | /// 7 | /// 1. main主线程输出的结果中会莫名其妙少一位,并不是从0到10的连续值。 8 | /// 2. child子线程输出的结果和main主线程输出的结果有重复。 9 | /// 10 | /// ```rust 11 | /// use std::thread; 12 | /// static mut V: i32 = 0; 13 | /// fn unsafe_seq() -> i32 { 14 | /// unsafe { 15 | /// V += 1; 16 | /// V 17 | /// } 18 | /// } 19 | /// fn main() { 20 | /// let child = thread::spawn(move || { 21 | /// for _ in 0..10 { 22 | /// unsafe_seq(); 23 | /// unsafe{println!("child : {}", V);} 24 | /// } 25 | /// }); 26 | /// for _ in 0..10 { 27 | /// unsafe_seq(); 28 | /// unsafe{println!("main : {}", V);} 29 | /// } 30 | /// child.join().unwrap(); 31 | /// } 32 | /// ``` 33 | pub fn unsafe_seq(){ 34 | unimplemented!(); 35 | } 36 | -------------------------------------------------------------------------------- /src/ch12/derive-new/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /src/ch12/derive-new/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "derive-new" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | 7 | [lib] 8 | proc-macro = true 9 | 10 | [dependencies] 11 | quote = "0.6" 12 | syn = "0.15" 13 | proc-macro2="0.4" -------------------------------------------------------------------------------- /src/ch12/derive-new/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate proc_macro; 2 | use { 3 | syn::{Token, DeriveInput, parse_macro_input}, 4 | quote::*, 5 | proc_macro2, 6 | self::proc_macro::TokenStream, 7 | }; 8 | 9 | #[proc_macro_derive(New)] 10 | pub fn derive(input: TokenStream) -> TokenStream { 11 | let ast = parse_macro_input!(input as DeriveInput); 12 | let result = match ast.data { 13 | syn::Data::Struct(ref s) => new_for_struct(&ast, &s.fields), 14 | _ => panic!("doesn't work with unions yet"), 15 | }; 16 | result.into() 17 | } 18 | 19 | fn new_for_struct(ast: &syn::DeriveInput,fields: &syn::Fields) -> proc_macro2::TokenStream 20 | { 21 | match *fields { 22 | syn::Fields::Named(ref fields) => { 23 | new_impl(&ast, Some(&fields.named), true) 24 | }, 25 | syn::Fields::Unit => { 26 | new_impl(&ast, None, false) 27 | }, 28 | syn::Fields::Unnamed(ref fields) => { 29 | new_impl(&ast, Some(&fields.unnamed), false) 30 | }, 31 | } 32 | } 33 | 34 | fn new_impl(ast: &syn::DeriveInput, 35 | fields: Option<&syn::punctuated::Punctuated>, 36 | named: bool) -> proc_macro2::TokenStream 37 | { 38 | let struct_name = &ast.ident; 39 | 40 | let unit = fields.is_none(); 41 | let empty = Default::default(); 42 | 43 | let fields: Vec<_> = fields.unwrap_or(&empty) 44 | .iter() 45 | .enumerate() 46 | .map(|(i, f)| FieldExt::new(f, i, named)).collect(); 47 | 48 | let args = fields.iter().map(|f| f.as_arg()); 49 | let inits = fields.iter().map(|f| f.as_init()); 50 | 51 | let inits = if unit { 52 | quote!() 53 | } else if named { 54 | quote![ { #(#inits),* } ] 55 | } else { 56 | quote![ ( #(#inits),* ) ] 57 | }; 58 | 59 | 60 | let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); 61 | let (new, doc) = ( 62 | syn::Ident::new("new", proc_macro2::Span::call_site()), 63 | format!("Constructs a new `{}`.", struct_name) 64 | ); 65 | quote! { 66 | impl #impl_generics #struct_name #ty_generics #where_clause { 67 | #[doc = #doc] 68 | pub fn #new(#(#args),*) -> Self { 69 | #struct_name #inits 70 | } 71 | } 72 | } 73 | } 74 | 75 | struct FieldExt<'a> { 76 | ty: &'a syn::Type, 77 | ident: syn::Ident, 78 | named: bool, 79 | } 80 | impl<'a> FieldExt<'a> { 81 | pub fn new(field: &'a syn::Field, idx: usize, named: bool) -> FieldExt<'a> { 82 | FieldExt { 83 | ty: &field.ty, 84 | ident: if named { 85 | field.ident.clone().unwrap() 86 | } else { 87 | syn::Ident::new(&format!("f{}", idx), proc_macro2::Span::call_site()) 88 | }, 89 | named: named, 90 | } 91 | } 92 | pub fn as_arg(&self) -> proc_macro2::TokenStream { 93 | let f_name = &self.ident; 94 | let ty = &self.ty; 95 | quote!(#f_name: #ty) 96 | } 97 | 98 | pub fn as_init(&self) -> proc_macro2::TokenStream { 99 | let f_name = &self.ident; 100 | let init = quote!(#f_name); 101 | if self.named { 102 | quote!(#f_name: #init) 103 | } else { 104 | quote!(#init) 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/ch12/derive-new/tests/test.rs: -------------------------------------------------------------------------------- 1 | use derive_new::New; 2 | // A struct with no fields. 3 | #[derive(New, PartialEq, Debug)] 4 | pub struct Foo {} 5 | // A struct with fields. 6 | #[derive(New, PartialEq, Debug)] 7 | pub struct Bar { 8 | pub x: i32, 9 | pub y: String, 10 | } 11 | // A unit struct. 12 | #[derive(New, PartialEq, Debug)] 13 | pub struct Baz; 14 | // A tuple struct 15 | #[derive(New, PartialEq, Debug)] 16 | pub struct Tuple(pub i32, pub i32); 17 | #[test] 18 | fn test_empty_struct() { 19 | let x = Foo::new(); 20 | assert_eq!(x, Foo {}); 21 | } 22 | #[test] 23 | fn test_simple_struct() { 24 | let x = Bar::new(42, "Hello".to_owned()); 25 | assert_eq!(x, Bar { x: 42, y: "Hello".to_owned() }); 26 | } 27 | #[test] 28 | fn test_unit_struct() { 29 | let x = Baz::new(); 30 | assert_eq!(x, Baz); 31 | } 32 | #[test] 33 | fn test_simple_tuple_struct() { 34 | let x = Tuple::new(5, 6); 35 | assert_eq!(x, Tuple(5, 6)); 36 | } 37 | 38 | 39 | #[derive(New, PartialEq, Debug)] 40 | pub struct Intersection<'scene> { 41 | pub object: &'scene Bar, 42 | pub normal: Foo, 43 | pub point: Foo, 44 | pub t: f64, 45 | } 46 | 47 | #[test] 48 | fn test_struct_with_lifetime() { 49 | let b = Bar::new(42, "Hello".to_owned()); 50 | let x = Intersection::new(&b, Foo::new(), Foo::new(), 42.0); 51 | assert_eq!(x, Intersection { object: &b, normal: Foo {}, point: Foo {}, t: 42.0 }); 52 | } 53 | 54 | // 55 | // #[derive(new, PartialEq, Debug)] 56 | // pub struct Fred { 57 | // #[new(value = "1 + 2")] 58 | // pub x: i32, 59 | // pub y: String, 60 | // #[new(value = "vec![-42, 42]")] 61 | // pub z: Vec, 62 | // } 63 | // // 64 | // #[test] 65 | // fn test_struct_with_values() { 66 | // let x = Fred::new("Fred".to_owned()); 67 | // assert_eq!(x, Fred { x: 3, y: "Fred".to_owned(), z: vec![-42, 42] }); 68 | // } 69 | -------------------------------------------------------------------------------- /src/ch12/hashmap_lite/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /src/ch12/hashmap_lite/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hashmap_lite" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /src/ch12/hashmap_lite/README.md: -------------------------------------------------------------------------------- 1 | # 说明 2 | 3 | 本crate是为了测试宏导入导出 -------------------------------------------------------------------------------- /src/ch12/hashmap_lite/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | macro_rules! hashmap { 3 | (@unit $($x:tt)*) => (()); 4 | (@count $($rest:expr),*) => 5 | (<[()]>::len(&[$(hashmap!(@unit $rest)),*])); 6 | ($($key:expr => $value:expr),* $(,)*) => { 7 | { 8 | let _cap = hashmap!(@count $($key),*); 9 | let mut _map = 10 | ::std::collections::HashMap::with_capacity(_cap); 11 | $( 12 | _map.insert($key, $value); 13 | )* 14 | _map 15 | } 16 | }; 17 | } 18 | 19 | // 测试$crate 20 | pub fn incr(x: u32) -> u32 { 21 | x+1 22 | } 23 | 24 | #[macro_export] 25 | macro_rules! inc { 26 | ($x:expr) => ( $crate::incr($x) ) 27 | } -------------------------------------------------------------------------------- /src/ch12/hashmap_lite/src/main.rs: -------------------------------------------------------------------------------- 1 | // Rust 2015 2 | // #[macro_use] extern crate hashmap_lite; 3 | 4 | // Rust 2018 5 | use hashmap_lite::hashmap; 6 | use hashmap_lite as hm; 7 | 8 | #[macro_use] 9 | mod macros { 10 | macro_rules! X { () => { Y!(); } } 11 | macro_rules! Y { () => {} } 12 | } 13 | 14 | fn main(){ 15 | let map = hashmap!{ 16 | "a" => 1, 17 | "b" => 2, 18 | }; 19 | assert_eq!(map["a"], 1); 20 | X!(); 21 | assert_eq!(hm::inc!(1), 2); 22 | } -------------------------------------------------------------------------------- /src/ch12/mod.rs: -------------------------------------------------------------------------------- 1 | //! 第十二章:元编程 2 | //! 3 | 4 | /// # Examples 5 | /// 6 | /// Basic usage: 7 | /// 8 | /// ``` 9 | /// pub fn title(){ 10 | /// println!("第12章:{}", "元编程"); 11 | /// } 12 | /// title(); 13 | /// ``` 14 | pub fn title(){ 15 | println!("第12章:{}", "元编程"); 16 | } 17 | 18 | pub mod reflect; 19 | pub mod macros; -------------------------------------------------------------------------------- /src/ch12/plugin_demo/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /src/ch12/plugin_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "plugin_demo" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | 9 | [lib] 10 | plugin = true 11 | -------------------------------------------------------------------------------- /src/ch12/plugin_demo/src/lib.rs: -------------------------------------------------------------------------------- 1 | // #![crate_type="dylib"] 2 | #![feature(plugin_registrar, rustc_private)] 3 | 4 | extern crate syntax; 5 | extern crate rustc; 6 | extern crate rustc_plugin; 7 | 8 | use self::syntax::parse::token; 9 | use self::syntax::tokenstream::TokenTree; 10 | use self::syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; 11 | use self::syntax::ext::build::AstBuilder; 12 | use self::syntax::ext::quote::rt::Span; 13 | use self::rustc_plugin::Registry; 14 | 15 | static ROMAN_NUMERALS: &'static [(&'static str, usize)] = &[ 16 | ("M", 1000), ("CM", 900), ("D", 500), ("CD", 400), 17 | ("C", 100), ("XC", 90), ("L", 50), ("XL", 40), 18 | ("X", 10), ("IX", 9), ("V", 5), ("IV", 4), 19 | ("I", 1)]; 20 | 21 | // 计算罗马数字,转换为阿拉伯数字 22 | fn expand_roman(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) 23 | -> Box { 24 | 25 | if args.len() != 1 { 26 | // 验证传入的参数不能为空,或者多于1个参数 27 | cx.span_err( 28 | sp, 29 | &format!("argument should be a single identifier, but got {} arguments", args.len())); 30 | return DummyResult::any(sp); // DummyResult为trait object,传递出错的位置信息 31 | } 32 | 33 | let text = match args[0] { 34 | // 验证传入的参数必须是标识符 token::Ident 35 | TokenTree::Token(_, token::Ident(s, _)) => s.to_string(), 36 | _ => { 37 | cx.span_err(sp, "argument should be a single identifier"); 38 | return DummyResult::any(sp); 39 | } 40 | }; 41 | let mut text = &*text; 42 | let mut total = 0; 43 | while !text.is_empty() { 44 | match ROMAN_NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) { 45 | Some(&(rn, val)) => { 46 | total += val; 47 | text = &text[rn.len()..]; 48 | } 49 | None => { 50 | cx.span_err(sp, "invalid Roman numeral"); 51 | return DummyResult::any(sp); 52 | } 53 | } 54 | } 55 | // MacEager枚举类型,记录了Rust语法结构 56 | // 此处为表达式类型,返回usize类型total和位置信息sp 57 | MacEager::expr(cx.expr_usize(sp, total)) 58 | } 59 | 60 | #[plugin_registrar] 61 | pub fn plugin_registrar_demo(reg: &mut Registry) { 62 | // 使用register_macro注册为宏 63 | reg.register_macro("roman_to_digit", expand_roman); 64 | } -------------------------------------------------------------------------------- /src/ch12/plugin_demo/tests/test.rs: -------------------------------------------------------------------------------- 1 | #![feature(plugin)] 2 | #![plugin(plugin_demo)] 3 | 4 | #[test] 5 | fn test_plugin() { 6 | assert_eq!(roman_to_digit!(MMXVIII), 2018); 7 | // // errors 8 | // assert_eq!(roman_to_digit!(M,X), 2018); 9 | // assert_eq!(roman_to_digit!(), 2018); 10 | // assert_eq!(roman_to_digit!(123), 2018); 11 | } -------------------------------------------------------------------------------- /src/ch12/reflect.rs: -------------------------------------------------------------------------------- 1 | /// # 使用Any进行反射 2 | /// 3 | /// Basic usage: 使用is函数进行类型判断 4 | /// 5 | /// ``` 6 | /// use std::any::{Any, TypeId}; 7 | /// 8 | /// enum E { H, He, Li} 9 | /// 10 | /// struct S { x: u8, y: u8, z: u16 } 11 | /// 12 | /// fn main() { 13 | /// let v1 = 0xc0ffee_u32; 14 | /// let v2 = E::He; 15 | /// let v3 = S { x: 0xde, y: 0xad, z: 0xbeef }; 16 | /// let v4 = "rust"; 17 | /// let mut a: &Any; // trait object 18 | /// a = &v1; 19 | /// assert!(a.is::()); 20 | /// // TypeId { t: 12849923012446332737 } 21 | /// println!("{:?}", TypeId::of::()); 22 | /// a = &v2; 23 | /// assert!(a.is::()); 24 | /// // TypeId { t: 15527215023668350898 } 25 | /// println!("{:?}", TypeId::of::()); 26 | /// a = &v3; 27 | /// assert!(a.is::()); 28 | /// // TypeId { t: 17868507538031848664 } 29 | /// println!("{:?}", TypeId::of::()); 30 | /// a = &v4; 31 | /// assert!(a.is::<&str>()); 32 | /// // TypeId { t: 1229646359891580772 } 33 | /// println!("{:?}", TypeId::of::<&str>()); 34 | /// } 35 | /// ``` 36 | /// 37 | /// Basic usage: 使用downcase_ref转换到具体类型 38 | /// 39 | /// ``` 40 | /// use std::any::Any; 41 | /// #[derive(Debug)] 42 | /// enum E { H, He, Li} 43 | /// struct S { x: u8, y: u8, z: u16 } 44 | /// fn print_any(a: &Any) { 45 | /// if let Some(v) = a.downcast_ref::() { 46 | /// println!("u32 {:x}", v); 47 | /// } else if let Some(v) = a.downcast_ref::() { 48 | /// println!("enum E {:?}", v); 49 | /// } else if let Some(v) = a.downcast_ref::() { 50 | /// println!("struct S {:x} {:x} {:x}", v.x, v.y, v.z); 51 | /// } else { 52 | /// println!("else!"); 53 | /// } 54 | /// } 55 | /// fn main() { 56 | /// print_any(& 0xc0ffee_u32); 57 | /// print_any(& E::He); 58 | /// print_any(& S{ x: 0xde, y: 0xad, z: 0xbeef }); 59 | /// print_any(& "rust"); 60 | /// print_any(& "hoge"); 61 | /// } 62 | /// ``` 63 | /// 64 | /// Basic usage: 使用Box 65 | /// 66 | /// ``` 67 | /// use std::any::Any; 68 | /// fn print_if_string(value: Box) { 69 | /// if let Ok(string) = value.downcast::() { 70 | /// println!("String (length {}): {}", string.len(), string); 71 | /// }else{ 72 | /// println!("Not String") 73 | /// } 74 | /// } 75 | /// fn main() { 76 | /// let my_string = "Hello World".to_string(); 77 | /// print_if_string(Box::new(my_string)); 78 | /// print_if_string(Box::new(0i8)); 79 | /// } 80 | /// ``` 81 | /// 82 | /// Basic usage: 非静态生命周期的类型未实现Any 83 | /// 84 | /// ``` 85 | /// use std::any::Any; 86 | /// struct UnStatic<'a> { x: &'a i32 } 87 | /// fn main() { 88 | /// let a = 42; 89 | /// let v = UnStatic { x: &a }; 90 | /// let mut any: &Any; 91 | /// //any = &v; // Compile Error! 92 | /// } 93 | /// ``` 94 | /// 95 | /// Basic usage: 使用静态生命周期类型的值创建UnStatic实例 96 | /// 97 | /// 正常编译 98 | /// 99 | /// ``` 100 | /// use std::any::Any; 101 | /// struct UnStatic<'a> { x: &'a i32 } 102 | /// static ANSWER: i32 = 42; 103 | /// fn main() { 104 | /// let v = UnStatic { x: &ANSWER }; 105 | /// let mut a: &Any; 106 | /// a = &v; 107 | /// assert!(a.is::()); 108 | /// } 109 | /// ``` 110 | pub fn any_function(){ 111 | unimplemented!(); 112 | } -------------------------------------------------------------------------------- /src/ch12/simple_proc_macro/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /src/ch12/simple_proc_macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "simple_proc_macro" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | 7 | [lib] 8 | proc-macro = true 9 | -------------------------------------------------------------------------------- /src/ch12/simple_proc_macro/src/lib.rs: -------------------------------------------------------------------------------- 1 | // #![feature(custom_attribute)] 2 | // #![feature(proc_macro_non_items)] 3 | 4 | extern crate proc_macro; 5 | use self::proc_macro::TokenStream; 6 | 7 | // 自定义派生属性 8 | #[proc_macro_derive(A)] 9 | pub fn derive(input: TokenStream) -> TokenStream { 10 | let _input = input.to_string(); 11 | assert!(_input.contains("struct A;")); 12 | r#" 13 | impl A { 14 | fn a(&self) -> String{ 15 | format!("hello from impl A") 16 | } 17 | } 18 | "#.parse().unwrap() 19 | } 20 | 21 | // 自定义编译器插件 22 | #[proc_macro_attribute] 23 | pub fn attr_with_args(args: TokenStream, input: TokenStream) 24 | -> TokenStream { 25 | let args = args.to_string(); 26 | let _input = input.to_string(); 27 | format!("fn foo() -> &'static str {{ {} }}", args) 28 | .parse().unwrap() 29 | } 30 | 31 | // Bang宏:定义hashmap! 32 | #[proc_macro] 33 | pub fn hashmap(input: TokenStream) -> TokenStream { 34 | // 转换input为字符串 35 | let _input = input.to_string(); 36 | // 将input字符串结尾的逗号去掉,否则在下面迭代中将报错 37 | let input = _input.trim_right_matches(','); 38 | // 用split将字符串分割为slice,然后用map去处理 39 | // 为了支持「"a" : 1」或 「"a" => 1」这样的语法 40 | let input: Vec = input.split(",").map(|n| { 41 | let mut data = if n.contains(":") { n.split(":") } 42 | else { n.split(" => ") }; 43 | let (key, value) = 44 | (data.next().unwrap(), data.next().unwrap()); 45 | format!("hm.insert({}, {})", key, value) 46 | }).collect(); 47 | let count: usize = input.len(); 48 | let tokens = format!(" 49 | {{ 50 | let mut hm = 51 | ::std::collections::HashMap::with_capacity({}); 52 | {} 53 | hm 54 | }}", count, 55 | input.iter().map(|n| format!("{};", n)).collect::() 56 | ); 57 | // parse函数会将字符串转为Result 58 | tokens.parse().unwrap() 59 | } 60 | -------------------------------------------------------------------------------- /src/ch12/simple_proc_macro/tests/test.rs: -------------------------------------------------------------------------------- 1 | // #![feature(custom_attribute)] 2 | // #![feature(proc_macro_non_items)] 3 | 4 | #![feature(proc_macro_hygiene)] 5 | 6 | 7 | use simple_proc_macro::{A, attr_with_args, hashmap}; 8 | 9 | // 自定义派生属性 10 | #[derive(A)] 11 | struct A; 12 | 13 | // 自定义编译器插件 14 | #[attr_with_args("Hello, Rust!")] 15 | fn foo() {} 16 | 17 | // 测试自定义派生属性 18 | #[test] 19 | fn test_derive_a() { 20 | assert_eq!("hello from impl A".to_string(), A.a()); 21 | } 22 | 23 | // 测试自定义编译器插件 24 | #[test] 25 | fn test_foo() { 26 | let r = foo(); 27 | assert_eq!(r, "Hello, Rust!") ; 28 | } 29 | 30 | // 测试Bang宏 31 | // 过程宏-bang宏还无法用于表达式位置,所以下面测试暂时会报错,等支持的时候应该就会通过 32 | // 相关issues:https://github.com/rust-lang/rust/issues/54727 33 | // https://github.com/rust-lang/blog.rust-lang.org/issues/285 34 | #[test] 35 | fn test_hashmap() { 36 | let hm = hashmap!{ "a" => 1,"b" => 2,"c" => 3}; 37 | assert_eq!(hm["c"], 3); 38 | let hm = hashmap!{ "a": 1, "b": 2,}; 39 | assert_eq!(hm["a"], 1); 40 | } 41 | -------------------------------------------------------------------------------- /src/ch13/callrust/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode 7 | c_src/main -------------------------------------------------------------------------------- /src/ch13/callrust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "callrust" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | libc="0.2.43" 9 | [lib] 10 | name = "callrust" 11 | crate-type = ["staticlib", "cdylib"] 12 | -------------------------------------------------------------------------------- /src/ch13/callrust/Node.js/database.js: -------------------------------------------------------------------------------- 1 | // 需要Node.js V10.7.0, N-API已稳定 2 | // 命令:node database.js 3 | const ffi = require('ffi-napi'); 4 | const lib = ffi.Library('../target/debug/libcallrust.dylib', { 5 | database_new: ['pointer', []], 6 | database_free: ['void', ['pointer']], 7 | database_insert: ['void', ['pointer']], 8 | database_query: ['uint32', ['pointer', 'string']], 9 | }); 10 | const Database = function() { 11 | this.ptr = lib.database_new(); 12 | }; 13 | Database.prototype.free = function() { 14 | lib.database_free(this.ptr); 15 | }; 16 | Database.prototype.insert = function() { 17 | lib.database_insert(this.ptr); 18 | }; 19 | Database.prototype.query = function(zip) { 20 | return lib.database_query(this.ptr, zip); 21 | }; 22 | const database = new Database(); 23 | try { 24 | database.insert(); 25 | const pop1 = database.query("10186") 26 | const pop2 = database.query("10852") 27 | console.log(pop2 - pop1); 28 | }finally { 29 | database.free(); 30 | } -------------------------------------------------------------------------------- /src/ch13/callrust/Python/database.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys, ctypes 3 | from ctypes import c_char_p, c_uint32, Structure, POINTER 4 | 5 | prefix = {'win32': ''}.get(sys.platform, '../target/debug/lib') 6 | extension = {'darwin': '.dylib', 'win32': '.dll'} \ 7 | .get(sys.platform, '.so') 8 | 9 | class DatabaseS(Structure): 10 | pass 11 | 12 | lib = ctypes.cdll.LoadLibrary(prefix + "callrust" + extension) 13 | 14 | # 必须以DatabaseS作为参数,否则会产生空指针 15 | lib.database_new.restype = POINTER(DatabaseS) 16 | lib.database_free.argtypes = (POINTER(DatabaseS), ) 17 | lib.database_insert.argtypes = (POINTER(DatabaseS), ) 18 | lib.database_query.argtypes = (POINTER(DatabaseS), c_char_p) 19 | lib.database_query.restype = c_uint32 20 | 21 | class Database: 22 | def __init__(self): 23 | self.obj = lib.database_new() 24 | def __enter__(self): 25 | return self 26 | def __exit__(self, exc_type, exc_value, traceback): 27 | lib.database_free(self.obj) 28 | def insert(self): 29 | lib.database_insert(self.obj) 30 | def query(self, zip): 31 | return lib.database_query(self.obj, zip.encode('utf-8')) 32 | with Database() as database: 33 | database.insert() 34 | pop1 = database.query("10186") 35 | pop2 = database.query("10852") 36 | print(pop2 - pop1) -------------------------------------------------------------------------------- /src/ch13/callrust/Ruby/database.rb: -------------------------------------------------------------------------------- 1 | # 命令:ruby database.rb 2 | require 'ffi' 3 | class Database < FFI::AutoPointer 4 | def self.release(ptr) 5 | Binding.free(ptr) 6 | end 7 | def insert 8 | Binding.insert(self) 9 | end 10 | def query(zip) 11 | Binding.query(self, zip) 12 | end 13 | module Binding 14 | extend FFI::Library 15 | # 因为我本地使用macOS,所以这动态库为.dylib 16 | ffi_lib "../target/debug/libcallrust.dylib" 17 | attach_function :new, :database_new, [], Database 18 | attach_function :free, :database_free, [Database], :void 19 | attach_function :insert, :database_insert, [Database], :void 20 | attach_function :query, :database_query, 21 | [Database, :string], :uint32 22 | end 23 | end 24 | database = Database::Binding.new 25 | database.insert 26 | pop1 = database.query("10186") 27 | pop2 = database.query("10852") 28 | puts pop2 - pop1 -------------------------------------------------------------------------------- /src/ch13/callrust/c_src/main.c: -------------------------------------------------------------------------------- 1 | #include "callrust.h" 2 | #include 3 | #include 4 | #include 5 | 6 | int main (void) { 7 | uint32_t numbers[6] = {1,2,3,4,5,6}; 8 | uint32_t sum = sum_of_even(numbers, 6); 9 | printf("%d\n", sum); 10 | 11 | uint32_t count = hm_chars("The taö of Rust"); 12 | printf("%d\n", count); 13 | 14 | char *song = batman_song(5); 15 | printf("%s\n", song); 16 | free_song(song); 17 | 18 | tuple_t initial = { .x = 10, .y = 20 }; 19 | tuple_t new = flip_things_around(initial); 20 | printf("(%d,%d)\n", new.x, new.y); 21 | 22 | database_t *database = database_new(); 23 | database_insert(database); 24 | uint32_t pop1 = database_query(database, "10186"); 25 | uint32_t pop2 = database_query(database, "10852"); 26 | database_free(database); 27 | printf("%d\n", pop2 - pop1); 28 | 29 | print_hello_from_rust(); 30 | 31 | match(); 32 | } -------------------------------------------------------------------------------- /src/ch13/callrust/makefile: -------------------------------------------------------------------------------- 1 | GCC_BIN ?= $(shell which gcc) 2 | CARGO_BIN ?= $(shell which cargo) 3 | run: clean build 4 | ./c_src/main 5 | clean: 6 | $(CARGO_BIN) clean 7 | rm -f ./c_src/main 8 | build: 9 | $(CARGO_BIN) build 10 | $(GCC_BIN) -o ./c_src/main ./c_src/main.c -Isrc -L ./target/debug -lcallrust -------------------------------------------------------------------------------- /src/ch13/callrust/src/callrust.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | uint32_t sum_of_even(const uint32_t *numbers, size_t length); 5 | 6 | char * batman_song(uint8_t length); 7 | void free_song(char *); 8 | 9 | uint32_t hm_chars(const char *str); 10 | 11 | void print_hello_from_rust(); 12 | 13 | typedef struct { 14 | uint32_t x; 15 | uint32_t y; 16 | } tuple_t; 17 | tuple_t flip_things_around(tuple_t); 18 | 19 | typedef struct database_S database_t; 20 | database_t * database_new(void); 21 | void database_free(database_t *); 22 | void database_insert(database_t *); 23 | uint32_t database_query(const database_t *, const char *zip); 24 | 25 | void match(); -------------------------------------------------------------------------------- /src/ch13/callrust/src/lib.rs: -------------------------------------------------------------------------------- 1 | use libc::{c_char, c_uint}; 2 | use std::ffi::{CStr, CString}; 3 | use std::iter; 4 | use std::slice; 5 | 6 | // 计算整数数组中奇数元素之和 7 | #[no_mangle] 8 | pub extern fn sum_of_even(n: *const c_uint, len: c_uint) -> c_uint 9 | { 10 | let numbers = unsafe { 11 | assert!(!n.is_null()); 12 | slice::from_raw_parts(n, len as usize) 13 | }; 14 | let sum = numbers.iter() 15 | .filter(|&v| v % 2 == 0) 16 | .fold(0, |acc, v| acc + v); 17 | sum as c_uint 18 | } 19 | 20 | // 检测字符串长度 21 | #[no_mangle] 22 | pub extern fn hm_chars(s: *const c_char) -> c_uint { 23 | let c_str = unsafe { 24 | assert!(!s.is_null()); 25 | // CStr会产生一个以“\n”字符数组的引用 26 | CStr::from_ptr(s) 27 | }; 28 | let r_str = c_str.to_str().unwrap(); 29 | r_str.chars().count() as c_uint 30 | } 31 | 32 | // 目的是输出一个字符串“boom nana nana nana Batman! boom” 33 | // 可以称其为“蝙蝠侠之歌”, "nana"可以重复 34 | #[no_mangle] 35 | pub extern fn batman_song(length: c_uint) -> *mut c_char { 36 | let mut song = String::from("boom "); 37 | song.extend(iter::repeat("nana ").take(length as usize)); 38 | song.push_str("Batman! boom"); 39 | let c_str_song = CString::new(song).unwrap(); 40 | c_str_song.into_raw() 41 | } 42 | 43 | // 手动在C语言中调用以便清理内存 44 | #[no_mangle] 45 | pub extern fn free_song(s: *mut c_char) { 46 | unsafe { 47 | if s.is_null() { return } 48 | CString::from_raw(s) 49 | }; 50 | } 51 | 52 | #[no_mangle] 53 | pub extern fn print_hello_from_rust() { 54 | println!("Hello from Rust"); 55 | } 56 | 57 | 58 | // 用结构体模拟元组传递给C 59 | #[repr(C)] 60 | pub struct Tuple { 61 | x: c_uint, 62 | y: c_uint, 63 | } 64 | 65 | // 方便Rust的(u32, u32)转为Tuple结构体 66 | impl From<(u32, u32)> for Tuple { 67 | fn from(tup: (u32, u32)) -> Tuple { 68 | Tuple { x: tup.0, y: tup.1 } 69 | } 70 | } 71 | 72 | // 方便Tuple结构体转为Rust的(u32, u32) 73 | impl From for (u32, u32) { 74 | fn from(tup: Tuple) -> (u32, u32) { 75 | (tup.x, tup.y) 76 | } 77 | } 78 | fn compute_tuple(tup: (u32, u32)) -> (u32, u32) { 79 | let (a, b) = tup; 80 | (b+1, a-1) 81 | } 82 | 83 | #[no_mangle] 84 | pub extern fn flip_things_around(tup: Tuple) -> Tuple { 85 | compute_tuple(tup.into()).into() 86 | } 87 | 88 | // 传递Rust抽象结构比如,结构体实例)给C语言 89 | // C语言使用Opaque类型,Rust使用Box 90 | use std::collections::HashMap; 91 | pub struct Database { 92 | data: HashMap, 93 | } 94 | impl Database { 95 | fn new() -> Database { 96 | Database { 97 | data: HashMap::new(), 98 | } 99 | } 100 | fn insert(&mut self) { 101 | for i in 0..100000 { 102 | let zip = format!("{:05}", i); 103 | self.data.insert(zip, i); 104 | } 105 | } 106 | fn get(&self, zip: &str) -> u32 { 107 | self.data.get(zip).cloned().unwrap_or(0) 108 | } 109 | } 110 | 111 | #[no_mangle] 112 | pub extern fn database_new() -> *mut Database { 113 | Box::into_raw(Box::new(Database::new())) 114 | } 115 | 116 | #[no_mangle] 117 | pub extern fn database_insert(ptr: *mut Database) { 118 | let database = unsafe { 119 | assert!(!ptr.is_null()); 120 | &mut *ptr 121 | }; 122 | database.insert(); 123 | } 124 | 125 | #[no_mangle] 126 | pub extern fn database_query(ptr: *const Database, 127 | zip: *const c_char) -> c_uint 128 | { 129 | let database = unsafe { 130 | assert!(!ptr.is_null()); 131 | &*ptr 132 | }; 133 | let zip = unsafe { 134 | assert!(!zip.is_null()); 135 | CStr::from_ptr(zip) 136 | }; 137 | let zip_str = zip.to_str().unwrap(); 138 | database.get(zip_str) 139 | } 140 | 141 | // 由Rust分配内存,就由Rust来释放内存 142 | #[no_mangle] 143 | pub extern fn database_free(ptr: *mut Database) { 144 | if ptr.is_null() { return } 145 | unsafe { Box::from_raw(ptr); } 146 | } 147 | 148 | // Rust 1.30 新加入的 `r#`语法,可以使用Rust关键字命名函数 149 | // 在C语言那边使用`match`函数名可调用 150 | #[no_mangle] 151 | pub extern fn r#match() { 152 | println!("Hello from Rust from r#match"); 153 | } -------------------------------------------------------------------------------- /src/ch13/ffi.rs: -------------------------------------------------------------------------------- 1 | /// # 与其他语言交互 2 | /// 3 | /// # 与C语言交互 4 | /// 5 | /// Basic usage: Rust中调用C标准库函数 6 | /// 7 | /// ```rust 8 | /// extern "C" { 9 | /// fn isalnum(input: i32) -> i32; 10 | /// } 11 | /// fn main() { 12 | /// unsafe { 13 | /// println!("Is 3 a number ? the answer is : {}", isalnum(3)); 14 | /// // println!("Is 'a' a number ? ", isalnum('a')); 15 | /// } 16 | /// } 17 | /// ``` 18 | /// 19 | /// 20 | pub fn hello_c(){ 21 | unimplemented!(); 22 | } 23 | 24 | /// # 与CPP语言交互 25 | /// 26 | /// Basic usage: 请看随书源码crate 27 | /// 28 | /// - rustcallcpp, Rust中调用CPP 29 | pub fn hello_cpp(){ 30 | unimplemented!(); 31 | } 32 | 33 | /// # C/Ruby/Python/Node.js中调用Rust函数 34 | /// 35 | /// Basic usage: 请看随书源码crate 36 | /// 37 | /// - callrust 38 | pub fn hello_rust(){ 39 | unimplemented!(); 40 | } -------------------------------------------------------------------------------- /src/ch13/global_alloc.rs: -------------------------------------------------------------------------------- 1 | /// # 全局分配器 2 | /// 3 | /// - Rust 1.28之前默认内存分配器:jemalloc 4 | /// - Rust 1.28内存分配器 : System,提供全局分配器,可自定义 5 | /// 6 | /// Basic usage: 自定义全局分配器 7 | /// 8 | /// ``` 9 | /// use std::alloc::{GlobalAlloc, System, Layout}; 10 | /// 11 | /// struct MyAllocator; 12 | /// 13 | /// unsafe impl GlobalAlloc for MyAllocator { 14 | /// unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 15 | /// System.alloc(layout) 16 | /// } 17 | /// unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { 18 | /// System.dealloc(ptr, layout) 19 | /// } 20 | /// } 21 | /// 22 | /// #[global_allocator] 23 | /// static GLOBAL: MyAllocator = MyAllocator; 24 | /// 25 | /// fn main() { 26 | /// // 此处Vec的内存会由GLOBAL全局分配器来分配 27 | /// let mut v = Vec::new(); 28 | /// v.push(1); 29 | /// } 30 | /// ``` 31 | /// 32 | /// 33 | /// Basic usage: 指定全局分配器为jemalloc 34 | /// 35 | /// 需要引入第三方包 jemallocator 36 | /// 37 | /// ``` 38 | /// extern crate jemallocator; 39 | /// use jemallacator::Jemalloc; 40 | /// #[global_allocator] 41 | /// static GLOBAL: Jemalloc = Jemalloc; 42 | /// ``` 43 | pub fn global_alloc(){ 44 | unimplemented!(); 45 | } -------------------------------------------------------------------------------- /src/ch13/hello_wasm/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode 7 | # output/* -------------------------------------------------------------------------------- /src/ch13/hello_wasm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello_wasm" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | 9 | [lib] 10 | path = "src/lib.rs" 11 | crate-type = ["cdylib"] 12 | -------------------------------------------------------------------------------- /src/ch13/hello_wasm/README.md: -------------------------------------------------------------------------------- 1 | # 安装wasm-gc 2 | 3 | ``` 4 | cargo install wasm-gc 5 | ``` 6 | 7 | # 生成wasm的三条命令: 8 | 9 | ``` 10 | $ cargo build --target wasm32-unknown-unknown 11 | $ cp target/wasm32-unknown-unknown/debug/hello_wasm.wasm output 12 | $ wasm-gc output/hello_wasm.wasm output/small_hello.wasm 13 | ``` -------------------------------------------------------------------------------- /src/ch13/hello_wasm/hello.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | hello wasm 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/ch13/hello_wasm/hello.js: -------------------------------------------------------------------------------- 1 | var mod; 2 | var imports = { 3 | logit: () => { 4 | console.log('this was invoked by Rust, written in JS'); 5 | }, 6 | hello: (ptr, len) => { 7 | var buf = new Uint8Array(mod.instance.exports.memory.buffer, ptr, len) 8 | var msg = new TextDecoder('utf8').decode(buf); 9 | alert(msg); 10 | } 11 | } 12 | fetch('output/small_hello.wasm') 13 | .then(response => response.arrayBuffer()) 14 | .then(bytes => WebAssembly.instantiate(bytes, {env: imports})) 15 | .then(module => { 16 | mod = module; 17 | module.instance.exports.add_one(41); 18 | }); 19 | -------------------------------------------------------------------------------- /src/ch13/hello_wasm/output/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhangHanDong/tao-of-rust-codes/49d8be60c01b8900e71941d0349825e08453e557/src/ch13/hello_wasm/output/.keep -------------------------------------------------------------------------------- /src/ch13/hello_wasm/output/hello_wasm.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhangHanDong/tao-of-rust-codes/49d8be60c01b8900e71941d0349825e08453e557/src/ch13/hello_wasm/output/hello_wasm.wasm -------------------------------------------------------------------------------- /src/ch13/hello_wasm/output/small_hello.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhangHanDong/tao-of-rust-codes/49d8be60c01b8900e71941d0349825e08453e557/src/ch13/hello_wasm/output/small_hello.wasm -------------------------------------------------------------------------------- /src/ch13/hello_wasm/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[link(wasm_import_module = "env")] 2 | extern "C" { 3 | pub fn logit(); 4 | pub fn hello(ptr: *const u8, len: u32); 5 | } 6 | #[no_mangle] 7 | pub extern "C" fn add_one(x: i32) { 8 | unsafe { 9 | logit(); 10 | let msg = format!("Hello world: {}", x + 1); 11 | hello(msg.as_ptr(), msg.len() as u32); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ch13/mod.rs: -------------------------------------------------------------------------------- 1 | //! 第十三章:超越安全边界 2 | //! 3 | 4 | /// # Examples 5 | /// 6 | /// Basic usage: 7 | /// 8 | /// ``` 9 | /// pub fn title(){ 10 | /// println!("第13章:{}", "超越安全边界"); 11 | /// } 12 | /// title(); 13 | /// ``` 14 | pub fn title(){ 15 | println!("第13章:{}", "超越安全边界"); 16 | } 17 | 18 | pub mod raw_pointer; 19 | pub mod unsafe_intro; 20 | pub mod security_abstract; 21 | pub mod non_null_pointer; 22 | pub mod panic_safety; 23 | pub mod global_alloc; 24 | pub mod ffi; 25 | pub mod wasm; -------------------------------------------------------------------------------- /src/ch13/non_null_pointer.rs: -------------------------------------------------------------------------------- 1 | /// # NonNull指针 2 | /// 3 | /// `NonNull`旨在成为`Unsafe Rust`默认的原生指针 4 | /// 5 | /// Basic usage: NonNull内置方法展示 6 | /// 7 | /// 允许开发者更安全地使用原生指针 8 | /// 9 | /// ```rust 10 | /// use std::ptr::{null, NonNull}; 11 | /// fn main(){ 12 | /// let ptr : NonNull = NonNull::dangling(); 13 | /// println!("{:p}", ptr); // 0x4 14 | /// let mut v = 42; 15 | /// let ptr : Option> = NonNull::new(&mut v); 16 | /// println!("{:?}", ptr); // Some(0x7fff73406a78) 17 | /// println!("{:?}", ptr.unwrap().as_ptr()); // 0x7fff73406a78 18 | /// println!("{}", unsafe{ptr.unwrap().as_mut()}); // 42 19 | /// let mut v = 42; 20 | /// let ptr = NonNull::from(&mut v); 21 | /// println!("{:?}", ptr); // 0x7fff73406a7c 22 | /// let null_p: *const i32 = null(); 23 | /// let ptr = NonNull::new(null_p as *mut i32); 24 | /// println!("{:?}",ptr); // None 25 | /// } 26 | /// ``` 27 | /// 28 | /// 29 | /// ```rust 30 | /// use std::mem; 31 | /// use std::ptr::NonNull; 32 | /// struct Foo { 33 | /// a: *mut u64, 34 | /// b: *mut u64, 35 | /// } 36 | /// struct FooUsingNonNull { 37 | /// a: *mut u64, 38 | /// b: NonNull<*mut u64>, 39 | /// } 40 | /// fn main() { 41 | /// println!("*mut u64: {} bytes", mem::size_of::<*mut u64>()); 42 | /// println!("NonNull<*mut u64>: {} bytes", 43 | /// mem::size_of::>()); 44 | /// println!("Option<*mut u64>: {} bytes", 45 | /// mem::size_of::>()); 46 | /// println!("Option>: {} bytes", 47 | /// mem::size_of::>>()); 48 | /// println!("Option: {} bytes", 49 | /// mem::size_of::>()); 50 | /// println!("Option: {} bytes", 51 | /// mem::size_of::>()); 52 | /// } 53 | /// ``` 54 | pub fn non_null_intro(){ 55 | unimplemented!(); 56 | } -------------------------------------------------------------------------------- /src/ch13/panic_safety.rs: -------------------------------------------------------------------------------- 1 | /// # 恐慌安全 2 | /// 3 | /// Basic usage: 示例 4 | /// 5 | /// 6 | /// 7 | /// ```rust 8 | /// impl Vec { 9 | /// fn push_all(&mut self, to_push: &[T]) { 10 | /// self.reserve(to_push.len()); 11 | /// unsafe { 12 | /// self.set_len(self.len() + to_push.len()); 13 | /// for (i, x) in to_push.iter().enumerate() { 14 | /// // x.clone() 方法可能发生恐慌 15 | /// // 所以整个push_all函数就不是恐慌安全的函数 16 | /// // 但是出于Rust的设计,这些未初始化的内存并不会被暴露出来 17 | /// self.ptr().offset(i as isize).write(x.clone()); 18 | /// } 19 | /// } 20 | /// } 21 | ///} 22 | /// ``` 23 | /// 24 | /// # 新增恐慌不安全函数示例 25 | /// 26 | /// ```rust 27 | /// 28 | /// struct A(u32); 29 | /// impl Drop for A { 30 | /// fn drop(&mut self) { 31 | /// println!("droping {} in A", self.0); 32 | /// } 33 | /// } 34 | /// 35 | /// unsafe fn panic_unsafe(x: &mut Vec, a: A) { 36 | /// x.push(a); 37 | /// x.reserve(10); 38 | /// x.set_len(10); // set_len并不会预分配内存 39 | /// panic!("panic in unsafe block"); 40 | /// } 41 | /// 42 | /// fn main(){ 43 | /// let mut x = vec![]; 44 | /// unsafe { 45 | /// // 该unsafe函数因为panic而暴露了未初始化内存 46 | /// panic_unsafe(&mut x, A(42)) 47 | /// } 48 | /// } 49 | /// ``` 50 | /// 51 | /// # 新增: 所以恐慌不安全的函数也无法用catch_unwind捕获 52 | /// 53 | /// 编译器会提示:`the type `&mut std::vec::Vec` may not be safely transferred across an unwind boundary` 54 | /// 55 | /// ```rust 56 | /// struct A(u32); 57 | /// 58 | /// impl Drop for A { 59 | /// fn drop(&mut self) { 60 | /// println!("droping {} in A", self.0); 61 | /// } 62 | /// } 63 | /// 64 | /// unsafe fn panic_unsafe(x: &mut Vec, a: A) { 65 | /// x.push(a); 66 | /// x.set_len(10); 67 | /// panic!("panic in unsafe block"); 68 | /// } 69 | /// 70 | /// fn main(){ 71 | /// let mut x = vec![]; 72 | /// unsafe { 73 | /// // 不能catch_unwind恐慌不安全的函数 74 | /// let result = std::panic::catch_unwind(|| { 75 | /// // 该unsafe函数因为panic而暴露了未初始化内存 76 | /// panic_unsafe(&mut x, A(42)) 77 | /// }); 78 | /// } 79 | /// } 80 | /// ``` 81 | pub fn panic_safety() { 82 | unimplemented!(); 83 | } 84 | -------------------------------------------------------------------------------- /src/ch13/raw_pointer.rs: -------------------------------------------------------------------------------- 1 | /// # 原生指针 2 | /// 3 | /// 用途: 4 | /// - 在需要的时候跳过Rust安全检查 5 | /// - 与C语言打交道 6 | /// 7 | /// Basic usage: 解引用原生指针 8 | /// 9 | /// ``` 10 | /// fn main() { 11 | /// let mut s = "hello".to_string(); 12 | /// let r1 = &s as *const String; 13 | /// let r2 = &mut s as *mut String; 14 | /// assert_eq!(r1, r2); 15 | /// let address = 0x7fff1d72307d; 16 | /// let r3 = address as *const String; 17 | /// unsafe { 18 | /// println!("r1 is: {}", *r1); 19 | /// println!("r2 is: {}", *r2); 20 | /// // Segmentation fault 21 | /// // assert_eq!(*r1, *r3) 22 | /// } 23 | /// } 24 | /// ``` 25 | /// 26 | /// 27 | /// Basic usage: 创建空指针 28 | /// 29 | /// ```rust 30 | /// fn main() { 31 | /// let p: *const u8 = std::ptr::null(); 32 | /// assert!(p.is_null()); 33 | /// let s: &str = "hello"; 34 | /// let ptr: *const u8 = s.as_ptr(); 35 | /// assert!(!ptr.is_null()); 36 | /// let mut s = [1, 2, 3]; 37 | /// let ptr: *mut u32 = s.as_mut_ptr(); 38 | /// assert!(!ptr.is_null()); 39 | /// } 40 | /// ``` 41 | /// 42 | /// Basic usage: 使用offset偏移量 43 | /// 44 | /// offset方法不能保证传入的偏移量合法,故为unsafe 45 | /// 46 | /// ```rust 47 | /// fn main() { 48 | /// let s: &str = "Rust"; 49 | /// let ptr: *const u8 = s.as_ptr(); 50 | /// unsafe { 51 | /// println!("{:?}", *ptr.offset(1) as char); // u 52 | /// println!("{:?}", *ptr.offset(3) as char); // t 53 | /// println!("{:?}", *ptr.offset(255) as char); // ÿ 有UB风险 54 | /// } 55 | /// } 56 | /// ``` 57 | /// 58 | /// Basic usage: 使用read/write 59 | /// 60 | /// read/write也是unsafe方法 61 | /// 62 | /// ```rust 63 | /// fn main() { 64 | /// let x = "hello".to_string(); 65 | /// let y: *const u8 = x.as_ptr(); 66 | /// unsafe { 67 | /// assert_eq!(y.read() as char, 'h'); 68 | /// } 69 | /// let x = [0, 1, 2, 3]; 70 | /// let y = x[0..].as_ptr() as *const [u32; 4]; 71 | /// unsafe { 72 | /// assert_eq!(y.read(), [0,1,2,3]); 73 | /// } 74 | /// let x = vec![0, 1, 2, 3]; 75 | /// let y = &x as *const Vec; 76 | /// unsafe { 77 | /// assert_eq!(y.read(), [0,1,2,3]); 78 | /// } 79 | /// let mut x = ""; 80 | /// let y = &mut x as *mut &str; 81 | /// let z = "hello"; 82 | /// unsafe { 83 | /// y.write(z); 84 | /// assert_eq!(y.read(), "hello"); 85 | /// } 86 | /// } 87 | /// ``` 88 | /// 89 | /// Basic usage: 使用replace/swap 90 | /// 91 | /// 也是unsafe方法,使用它们要注意自引用问题 92 | /// 93 | /// ```rust 94 | /// fn main() { 95 | /// let mut v: Vec = vec![1, 2]; 96 | /// let v_ptr : *mut i32 = v.as_mut_ptr(); 97 | /// unsafe{ 98 | /// let old_v = v_ptr.replace(5); 99 | /// assert_eq!(1, old_v); 100 | /// assert_eq!([5, 2], &v[..]); 101 | /// } 102 | /// let mut v: Vec = vec![1, 2]; 103 | /// let v_ptr = &mut v as *mut Vec; 104 | /// unsafe{ 105 | /// let old_v = v_ptr.replace(vec![3,4,5]); 106 | /// assert_eq!([1, 2], &old_v[..]); 107 | /// assert_eq!([3, 4, 5], &v[..]); 108 | /// } 109 | /// let mut array = [0, 1, 2, 3]; 110 | /// let x = array[0..].as_mut_ptr() as *mut [u32; 2]; 111 | /// let y = array[1..].as_mut_ptr() as *mut [u32; 2]; 112 | /// unsafe { 113 | /// assert_eq!([0, 1], x.read()); 114 | /// assert_eq!([1, 2], y.read()); 115 | /// x.swap(y); 116 | /// assert_eq!([1, 0, 1, 3], array); 117 | /// } 118 | ///} 119 | ///``` 120 | pub fn raw_pointer(){ 121 | unimplemented!(); 122 | } -------------------------------------------------------------------------------- /src/ch13/rustcallcapp/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | .DS_Store 6 | .vscode -------------------------------------------------------------------------------- /src/ch13/rustcallcapp/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rustcallcapp" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | 9 | [build-dependencies] 10 | cc = "1.0" 11 | -------------------------------------------------------------------------------- /src/ch13/rustcallcapp/build.rs: -------------------------------------------------------------------------------- 1 | extern crate cc; 2 | fn main() { 3 | // 相当于执行 4 | // 1. `g++ -Wall -std=c++14 -c sorting.cpp`,使用g++编译sorting.cpp文件 5 | // 2. `ar rc libsorting.a sorting.o`,通过ar制作一份静态库libsorting.a 6 | cc::Build::new() 7 | .cpp(true) 8 | .warnings(true) 9 | .flag("-Wall") 10 | .flag("-std=c++14") 11 | .flag("-c") 12 | .file("cpp_src/sorting.cpp") 13 | .compile("sorting"); 14 | // 也可以使用Command::new("g++")来组装命令,但是cc更方便。 15 | } -------------------------------------------------------------------------------- /src/ch13/rustcallcapp/cpp_src/sorting.cpp: -------------------------------------------------------------------------------- 1 | #include "sorting.h" 2 | void interop_sort(int numbers[], size_t size) 3 | { 4 | int* start = &numbers[0]; 5 | int* end = &numbers[0] + size; 6 | std::sort(start, end, [](int x, int y) { return x > y; }); 7 | } -------------------------------------------------------------------------------- /src/ch13/rustcallcapp/cpp_src/sorting.h: -------------------------------------------------------------------------------- 1 | #ifndef __SORTING_H__ 2 | #define __SORTING_H__ "sorting.h" 3 | #include 4 | #include 5 | #include 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | void interop_sort(int[], size_t); 10 | #ifdef __cplusplus 11 | } 12 | #endif 13 | #endif -------------------------------------------------------------------------------- /src/ch13/rustcallcapp/src/main.rs: -------------------------------------------------------------------------------- 1 | // 链接名为libsorting的静态库 2 | #[link(name = "sorting", kind = "static")] 3 | extern { 4 | // 绑定CPP中的interop_sort函数 5 | // 注意参数类型要和CPP中的类型相对应 6 | fn interop_sort(arr: &[i32;10], n: u32); 7 | } 8 | 9 | // 对interop_sort函数的安全抽象 10 | pub fn sort_from_cpp(arr: &[i32;10], n: u32) { 11 | unsafe { 12 | interop_sort(arr, n); 13 | } 14 | } 15 | fn main() { 16 | let my_arr : [i32; 10] = [10, 42, -9, 12, 8, 25, 7, 13, 55, -1]; 17 | println!("Before sorting..."); 18 | println!("{:?}\n", my_arr); 19 | sort_from_cpp(&my_arr, 10); 20 | println!("After sorting..."); 21 | println!("{:?}", my_arr); 22 | } -------------------------------------------------------------------------------- /src/ch13/unsafe_intro.rs: -------------------------------------------------------------------------------- 1 | /// # Unsafe Rust介绍 2 | /// 3 | /// - unsafe关键字和unsafe块 4 | /// - 什么情况下需要用unsafe? 5 | /// - 什么情况下函数需要标记unsafe ? 6 | /// - 什么情况下trait需要标记unsafe ? 7 | /// - 什么情况下需要使用unsafe块 ? 8 | /// 9 | /// Basic usage: Unsafe中依旧会进行借用检查 10 | /// 11 | /// 12 | /// `error[E0502]`: cannot borrow `a` as mutable because it is also borrowed as immutable 13 | /// 14 | /// ``` 15 | /// fn main(){ 16 | /// unsafe { 17 | /// let mut a = "hello"; 18 | /// let b = &a; 19 | /// let c = &mut a; 20 | /// } 21 | /// } 22 | /// ``` 23 | /// 24 | /// Basic usage: Unsafe块示意 25 | /// 26 | /// ``` 27 | /// fn main() { 28 | /// let hello = vec![104, 101, 108, 108, 111]; 29 | /// let hello = unsafe { 30 | /// // 该函数为unsafe函数 31 | /// String::from_utf8_unchecked(hello) 32 | /// }; 33 | /// assert_eq!("hello", hello); 34 | /// } 35 | /// ``` 36 | /// 37 | /// Basic usage: 访问和修改可变静态变量 38 | /// 39 | /// ```rust 40 | /// static mut COUNTER: u32 = 0; 41 | /// fn main() { 42 | /// let inc = 3; 43 | /// unsafe { 44 | /// COUNTER += inc; 45 | /// println!("COUNTER: {}", COUNTER); 46 | /// } 47 | /// } 48 | /// ``` 49 | pub fn unsafe_intro(){ 50 | unimplemented!(); 51 | } 52 | 53 | /// # Union联合体 54 | /// 55 | /// 也叫共用体、Untagged Union 56 | /// 57 | /// Basic usage: 使用Union和Struct来模拟Enum - V1 58 | /// 59 | /// Error: 当前Union不支持Non-Copy类型 60 | /// 61 | /// ```rust 62 | /// // #![feature(untagged_unions)] 63 | /// #[repr(C)] 64 | /// union U { 65 | /// i: i32, 66 | /// f: f32, 67 | /// } 68 | /// #[repr(C)] 69 | /// struct Value{ 70 | /// tag: u8, 71 | /// value: U, 72 | /// } 73 | /// #[repr(C)] 74 | /// union MyZero { 75 | /// i: Value, 76 | /// f: Value, 77 | /// } 78 | /// enum MyEnumZero { 79 | /// I(i32), 80 | /// F(f32), 81 | /// } 82 | /// fn main(){ 83 | /// let int_0 = MyZero{i: Value{tag: b'0', value: U { i: 0 } } }; 84 | /// let float_0 = MyZero{i: Value{tag: b'1', value: U { f: 0.0 } } }; 85 | /// } 86 | /// ``` 87 | /// 88 | /// Basic usage: 使用Union和Struct来模拟Enum - V2 89 | /// 90 | /// 91 | /// ```rust 92 | /// #[repr(u32)] 93 | /// enum Tag { I, F } 94 | /// #[repr(C)] 95 | /// union U { 96 | /// i: i32, 97 | /// f: f32, 98 | /// } 99 | /// #[repr(C)] 100 | /// struct Value { 101 | /// tag: Tag, 102 | /// u: U, 103 | /// } 104 | /// fn is_zero(v: Value) -> bool { 105 | /// unsafe { 106 | /// match v { 107 | /// Value { tag: Tag::I, u: U { i: 0 } } => true, 108 | /// Value { tag: Tag::F, u: U { f: 0.0 } } => true, 109 | /// _ => false, 110 | /// } 111 | /// } 112 | /// } 113 | /// fn main() { 114 | /// let int_0 = Value{tag: Tag::I, u: U{i: 0}}; 115 | /// let float_0 = Value{tag: Tag::F, u: U{f: 0.0}}; 116 | /// assert_eq!(true, is_zero(int_0)); 117 | /// assert_eq!(true, is_zero(float_0)); 118 | /// assert_eq!(4, std::mem::size_of::()); 119 | /// } 120 | /// ``` 121 | /// 122 | /// Basic usage: 访问Union中未初始化的字段 123 | /// 124 | /// 虽然未报错,但该用法不安全 125 | /// 126 | /// ```rust 127 | /// #[repr(C)] 128 | /// union U { 129 | /// i: i32, 130 | /// f: f32, 131 | /// } 132 | /// fn main() { 133 | /// let u = U{i: 1}; 134 | /// let i =unsafe{ 135 | /// u.f 136 | /// }; 137 | /// // 0.000000000000000000000000000000000000000000001 138 | /// println!("{}", i); 139 | /// // 对于一个联合体来说,不能同时使用两个字段 140 | /// // 当然也不能同时出借两个字段的可变借用 141 | /// // unsafe{ 142 | /// // let i = &mut u.i; 143 | /// // let f = &mut u.f; 144 | /// // }; 145 | /// } 146 | /// ``` 147 | pub fn union_demo(){ 148 | unimplemented!(); 149 | } -------------------------------------------------------------------------------- /src/ch13/wasm-bindgen-demo/.appveyor.yml: -------------------------------------------------------------------------------- 1 | install: 2 | - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe 3 | - if not defined RUSTFLAGS rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain nightly 4 | - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin 5 | - rustc -V 6 | - cargo -V 7 | 8 | build: false 9 | 10 | test_script: 11 | - cargo test --locked 12 | -------------------------------------------------------------------------------- /src/ch13/wasm-bindgen-demo/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | node_modules/ 5 | pkg/ 6 | bin/ 7 | wasm-pack.log -------------------------------------------------------------------------------- /src/ch13/wasm-bindgen-demo/.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | sudo: false 3 | 4 | cache: cargo 5 | 6 | matrix: 7 | include: 8 | 9 | # Builds with wasm-pack. 10 | - rust: beta 11 | env: RUST_BACKTRACE=1 12 | addons: 13 | firefox: latest 14 | chrome: stable 15 | before_script: 16 | - (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update) 17 | - (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate) 18 | - cargo install-update -a 19 | - curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f 20 | script: 21 | - cargo generate --git . --name testing 22 | # Having a broken Cargo.toml (in that it has curlies in fields) anywhere 23 | # in any of our parent dirs is problematic. 24 | - mv Cargo.toml Cargo.toml.tmpl 25 | - cd testing 26 | - wasm-pack build 27 | - wasm-pack test --chrome --firefox --headless 28 | 29 | # Builds on nightly. 30 | - rust: nightly 31 | env: RUST_BACKTRACE=1 32 | before_script: 33 | - (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update) 34 | - (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate) 35 | - cargo install-update -a 36 | - rustup target add wasm32-unknown-unknown 37 | script: 38 | - cargo generate --git . --name testing 39 | - mv Cargo.toml Cargo.toml.tmpl 40 | - cd testing 41 | - cargo check 42 | - cargo check --target wasm32-unknown-unknown 43 | - cargo check --no-default-features 44 | - cargo check --target wasm32-unknown-unknown --no-default-features 45 | - cargo check --no-default-features --features console_error_panic_hook 46 | - cargo check --target wasm32-unknown-unknown --no-default-features --features console_error_panic_hook 47 | - cargo check --no-default-features --features "console_error_panic_hook wee_alloc" 48 | - cargo check --target wasm32-unknown-unknown --no-default-features --features "console_error_panic_hook wee_alloc" 49 | 50 | # Builds on beta. 51 | - rust: beta 52 | env: RUST_BACKTRACE=1 53 | before_script: 54 | - (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update) 55 | - (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate) 56 | - cargo install-update -a 57 | - rustup target add wasm32-unknown-unknown 58 | script: 59 | - cargo generate --git . --name testing 60 | - mv Cargo.toml Cargo.toml.tmpl 61 | - cd testing 62 | - cargo check 63 | - cargo check --target wasm32-unknown-unknown 64 | - cargo check --no-default-features 65 | - cargo check --target wasm32-unknown-unknown --no-default-features 66 | - cargo check --no-default-features --features console_error_panic_hook 67 | - cargo check --target wasm32-unknown-unknown --no-default-features --features console_error_panic_hook 68 | # Note: no enabling the `wee_alloc` feature here because it requires 69 | # nightly for now. 70 | -------------------------------------------------------------------------------- /src/ch13/wasm-bindgen-demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasm-bindgen-demo" 3 | version = "0.1.0" 4 | authors = ["blackanger "] 5 | 6 | [lib] 7 | crate-type = ["cdylib", "rlib"] 8 | 9 | [features] 10 | default = ["console_error_panic_hook"] 11 | 12 | [dependencies] 13 | cfg-if = "0.1.2" 14 | wasm-bindgen = "0.2" 15 | 16 | # The `console_error_panic_hook` crate provides better debugging of panics by 17 | # logging them with `console.error`. This is great for development, but requires 18 | # all the `std::fmt` and `std::panicking` infrastructure, so isn't great for 19 | # code size when deploying. 20 | console_error_panic_hook = { version = "0.1.1", optional = true } 21 | 22 | # `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size 23 | # compared to the default allocator's ~10K. It is slower than the default 24 | # allocator, however. 25 | # 26 | # Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now. 27 | wee_alloc = { version = "0.4.2", optional = true } 28 | 29 | [dev-dependencies] 30 | wasm-bindgen-test = "0.2" 31 | 32 | [profile.release] 33 | # Tell `rustc` to optimize for small code size. 34 | opt-level = "s" 35 | -------------------------------------------------------------------------------- /src/ch13/wasm-bindgen-demo/LICENSE_MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 blackanger 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /src/ch13/wasm-bindgen-demo/README.md: -------------------------------------------------------------------------------- 1 | # 参考 wasm-bindgen指南 2 | 3 | [wasm-bindgen指南](https://rustwasm.github.io/wasm-bindgen/introduction.html) 4 | 5 | --- 6 | 7 | 8 | 9 | # 🦀🕸️ `wasm-pack-template` 10 | 11 | A template for kick starting a Rust and WebAssembly project using 12 | [`wasm-pack`](https://github.com/rustwasm/wasm-pack). 13 | 14 | This template is designed for compiling Rust libraries into WebAssembly and 15 | publishing the resulting package to NPM. 16 | 17 | * Want to use the published NPM package in a Website? [Check out 18 | `create-wasm-app`.](https://github.com/rustwasm/create-wasm-app) 19 | * Want to make a monorepo-style Website without publishing to NPM? Check out 20 | [`rust-webpack-template`](https://github.com/rustwasm/rust-webpack-template) 21 | and/or 22 | [`rust-parcel-template`](https://github.com/rustwasm/rust-parcel-template). 23 | 24 | ## 🔋 Batteries Included 25 | 26 | * [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating 27 | between WebAssembly and JavaScript. 28 | * [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook) 29 | for logging panic messages to the developer console. 30 | * [`wee_alloc`](https://github.com/rustwasm/wee_alloc), an allocator optimized 31 | for small code size. 32 | 33 | ## 🚴 Usage 34 | 35 | ### 🐑 Use `cargo generate` to Clone this Template 36 | 37 | [Learn more about `cargo generate` here.](https://github.com/ashleygwilliams/cargo-generate) 38 | 39 | ``` 40 | cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project 41 | cd my-project 42 | ``` 43 | 44 | ### 🛠️ Build with `wasm-pack build` 45 | 46 | ``` 47 | wasm-pack build 48 | ``` 49 | 50 | ### 🔬 Test in Headless Browsers with `wasm-pack test` 51 | 52 | ``` 53 | wasm-pack test --headless --firefox 54 | ``` 55 | 56 | ### 🎁 Publish to NPM with `wasm-pack publish` 57 | 58 | ``` 59 | wasm-pack publish 60 | ``` 61 | -------------------------------------------------------------------------------- /src/ch13/wasm-bindgen-demo/define.js: -------------------------------------------------------------------------------- 1 | export function hello(ptr, len) { 2 | var buf = new Uint8Array(mod.instance.exports.memory.buffer, ptr, len) 3 | var msg = new TextDecoder('utf8').decode(buf); 4 | alert(msg); 5 | } 6 | -------------------------------------------------------------------------------- /src/ch13/wasm-bindgen-demo/index.js: -------------------------------------------------------------------------------- 1 | 2 | const js = import("./wasm_bindgen_demo"); 3 | 4 | js.then(js => { 5 | js.greet("World!"); 6 | }); 7 | -------------------------------------------------------------------------------- /src/ch13/wasm-bindgen-demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "serve": "webpack-dev-server" 4 | }, 5 | "devDependencies": { 6 | "html-webpack-plugin": "^3.2.0", 7 | "webpack": "^4.0.1", 8 | "webpack-cli": "^3.1.1", 9 | "webpack-dev-server": "^3.1.0" 10 | } 11 | } -------------------------------------------------------------------------------- /src/ch13/wasm-bindgen-demo/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate cfg_if; 2 | extern crate wasm_bindgen; 3 | 4 | mod utils; 5 | 6 | use cfg_if::cfg_if; 7 | use wasm_bindgen::prelude::*; 8 | 9 | cfg_if! { 10 | // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global 11 | // allocator. 12 | if #[cfg(feature = "wee_alloc")] { 13 | extern crate wee_alloc; 14 | #[global_allocator] 15 | static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; 16 | } 17 | } 18 | 19 | #[wasm_bindgen] 20 | extern { 21 | fn alert(s: &str); 22 | } 23 | 24 | #[wasm_bindgen] 25 | pub fn greet() { 26 | alert("Hello, wasm-bindgen-demo!"); 27 | } 28 | -------------------------------------------------------------------------------- /src/ch13/wasm-bindgen-demo/src/utils.rs: -------------------------------------------------------------------------------- 1 | use cfg_if::cfg_if; 2 | 3 | cfg_if! { 4 | // When the `console_error_panic_hook` feature is enabled, we can call the 5 | // `set_panic_hook` function at least once during initialization, and then 6 | // we will get better error messages if our code ever panics. 7 | // 8 | // For more details see 9 | // https://github.com/rustwasm/console_error_panic_hook#readme 10 | if #[cfg(feature = "console_error_panic_hook")] { 11 | extern crate console_error_panic_hook; 12 | pub use self::console_error_panic_hook::set_once as set_panic_hook; 13 | } else { 14 | #[inline] 15 | pub fn set_panic_hook() {} 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/ch13/wasm-bindgen-demo/tests/web.rs: -------------------------------------------------------------------------------- 1 | //! Test suite for the Web and headless browsers. 2 | 3 | #![cfg(target_arch = "wasm32")] 4 | 5 | extern crate wasm_bindgen_test; 6 | use wasm_bindgen_test::*; 7 | 8 | wasm_bindgen_test_configure!(run_in_browser); 9 | 10 | #[wasm_bindgen_test] 11 | fn pass() { 12 | assert_eq!(1 + 1, 2); 13 | } 14 | -------------------------------------------------------------------------------- /src/ch13/wasm-bindgen-demo/wasm_bindgen_demo.d.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | -------------------------------------------------------------------------------- /src/ch13/wasm-bindgen-demo/wasm_bindgen_demo.js: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | 3 | -------------------------------------------------------------------------------- /src/ch13/wasm-bindgen-demo/wasm_bindgen_demo_bg.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhangHanDong/tao-of-rust-codes/49d8be60c01b8900e71941d0349825e08453e557/src/ch13/wasm-bindgen-demo/wasm_bindgen_demo_bg.wasm -------------------------------------------------------------------------------- /src/ch13/wasm-bindgen-demo/webpack.config.js: -------------------------------------------------------------------------------- 1 | // webpack.config.js 2 | const path = require('path'); 3 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 4 | 5 | module.exports = { 6 | entry: "./index.js", 7 | output: { 8 | path: path.resolve(__dirname, "dist"), 9 | filename: "index.js", 10 | }, 11 | plugins: [ 12 | new HtmlWebpackPlugin({ 13 | title: "Getting started with WASM" 14 | }) 15 | ], 16 | mode: "development" 17 | }; -------------------------------------------------------------------------------- /src/ch13/wasm.rs: -------------------------------------------------------------------------------- 1 | /// # WebAssmebly介绍 2 | /// 3 | /// Basic usage: 使用https://webassembly.studio/ 创建WASM模板 4 | /// 5 | /// 通过项目完整介绍wasm,配合书本内容阅读 6 | /// 7 | /// 项目1: 「使用WebAssembly内存和JS交互」- 完整代码地址 https://webassembly.studio/?f=asqnsl6ru3o 8 | /// 项目2: 「表格与动态链接」 - 完整代码地址 https://webassembly.studio/?f=ottwfve7all 9 | /// 10 | /// Basic usage: Rust开发WebAssembly 11 | /// 12 | /// 相关crate 13 | /// 14 | /// - hello_wasm 15 | pub fn wasm(){ 16 | unimplemented!(); 17 | } -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(const_fn)] 2 | #![feature(never_type)] 3 | #![feature(specialization)] 4 | #![feature(unboxed_closures, fn_traits)] 5 | //! 《Rust编程之道》 6 | //! 7 | //! 作者:张汉东 8 | //! 9 | //! 这里记录本书中涉及的所有示例代码。 10 | //! 11 | //! [源码仓库 : ZhangHanDong/tao-of-rust-codes](https://github.com/ZhangHanDong/tao-of-rust-codes) 12 | //!
13 | //! 14 | //!
15 | //!
16 | //! 17 | //! 正文从 [第一章: 新时代的语言][ch1] 开始。 18 | //! 19 | //! Rust安装的所有细节可以在 [附录A][appendix] 中找到。 20 | //! 21 | //! [appendix]: ../../doc/tao_of_rust/appendix/index.html 22 | //! [ch1]: ../../doc/tao_of_rust/ch1/index.html 23 | //!
24 | //!
25 | //! 28 | //!
29 | 30 | #![doc( 31 | html_playground_url = "https://play.rust-lang.org/", 32 | test(no_crate_inject, attr(deny(warnings))), 33 | test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) 34 | )] 35 | 36 | pub mod ch01; 37 | pub mod ch02; 38 | pub mod ch03; 39 | pub mod ch04; 40 | pub mod ch05; 41 | pub mod ch06; 42 | pub mod ch07; 43 | pub mod ch08; 44 | pub mod ch09; 45 | pub mod ch10; 46 | pub mod ch11; 47 | pub mod ch12; 48 | pub mod ch13; 49 | 50 | pub mod appendix; 51 | --------------------------------------------------------------------------------