├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── additional-references ├── 3.1 闭包 Closure.md ├── 3.2 迭代器 Iterator.md ├── 3.3 智能指针.md └── assets │ ├── 2022-10-31-IMG_0802.jpg │ ├── 2022-11-23-trpl04-04.svg │ ├── 2023-01-12-153248.png │ ├── 2023-02-01-082322.png │ ├── 2023-02-01-082744.png │ ├── 2023-06-22-024342.png │ ├── 97a6byy90566585499eabf4feda14783.jpg │ └── c1e1c1909b761cfa3348115bb417d4d4.png ├── attribute-macro ├── Cargo.toml └── src │ └── lib.rs ├── demos └── blockchain-rust │ ├── .gitignore │ ├── Cargo.toml │ ├── Merkle_Tree tx.png │ ├── README.md │ ├── merkle_tree.jpg │ └── src │ ├── block.rs │ ├── blockchain.rs │ ├── cli.rs │ ├── errors.rs │ ├── main.rs │ ├── server.rs │ ├── transaction.rs │ ├── utxoset.rs │ └── wallets.rs ├── derive-macro ├── Cargo.toml └── src │ └── lib.rs ├── function-like-macro ├── Cargo.toml └── src │ └── lib.rs ├── images ├── Dim Invest.md ├── Dim Search.md ├── chatdata_training_examples.md ├── invest shorts.md ├── prelude_traits.png ├── smart_pointers.png └── traits_fetures.png ├── module-five ├── .gitignore ├── Cargo.toml ├── examples │ └── main.rs └── src │ ├── asyn_programming │ ├── async_await.rs │ └── mod.rs │ ├── ccur_programming │ ├── create_thread.rs │ ├── mod.rs │ └── share_resource.rs │ └── lib.rs ├── module-four ├── .gitignore ├── Cargo.toml ├── example.txt ├── examples │ └── main.rs ├── rust.txt ├── src │ ├── error_handle │ │ ├── error_handle.rs │ │ ├── error_handle_example.rs │ │ └── mod.rs │ ├── lib.rs │ ├── project_management │ │ └── mod.rs │ └── project_tests │ │ ├── doc_test.rs │ │ ├── mod.rs │ │ └── unit_test.rs └── tests │ └── add_test.rs ├── module-one ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── examples │ └── main.rs ├── hello_cargo │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── hello_rust │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── main ├── main.rs ├── rust.txtr └── src │ ├── advance_data_types │ ├── closure.rs │ ├── enums.rs │ ├── func.rs │ ├── generics.rs │ ├── mod.rs │ ├── quotation.rs │ ├── set.rs │ ├── string.rs │ └── structs.rs │ ├── basic_data_types │ ├── compound.rs │ ├── mod.rs │ └── scalar.rs │ ├── comment │ ├── comment.rs │ └── mod.rs │ ├── control │ ├── circle.rs │ ├── mod.rs │ └── model_match.rs │ ├── lib.rs │ └── variable_mutability │ ├── mod.rs │ └── variable_mutability.rs ├── module-six ├── .gitignore ├── Cargo.toml ├── examples │ └── main.rs └── src │ ├── declarative_macros │ ├── declarative_macros.rs │ └── mod.rs │ ├── lib.rs │ ├── procedural_macros │ ├── attribute_macros.rs │ ├── derive_macro.rs │ ├── function_like_macros.rs │ └── mod.rs │ └── unsafe_rust │ ├── access_or_modify_static_var.rs │ ├── call_unsafe_method.rs │ ├── deref_raw_pointers.rs │ ├── impl_unsafe_trait.rs │ └── mod.rs ├── module-three ├── .gitignore ├── Cargo.toml ├── examples │ └── main.rs └── src │ ├── lib.rs │ ├── trait_advance │ ├── mod.rs │ ├── trait_closure.rs │ ├── trait_iterator.rs │ └── trait_smart_pointer.rs │ └── type_advance │ ├── boxs.rs │ ├── mod.rs │ ├── mut_container.rs │ ├── phantomdata.rs │ └── pin.rs ├── module-two ├── .gitignore ├── Cargo.toml ├── examples │ ├── main │ └── main.rs └── src │ ├── borrow_lifetime │ ├── borrow_rules.rs │ ├── lifetime.rs │ ├── lifetime_params.rs │ └── mod.rs │ ├── lib.rs │ ├── ownership │ ├── dynamic_sized_type.rs │ ├── dynamic_sized_type_intro.rs │ ├── mod.rs │ ├── other_sized_types.rs │ ├── share_ownership.rs │ ├── sized_types.rs │ └── sized_types_intro.rs │ └── traits │ ├── mod.rs │ ├── trait_intro.rs │ ├── trait_object.rs │ ├── trait_ownership.rs │ ├── trait_shared_behavior.rs │ └── trait_type_convert.rs ├── rust-co-learn.md ├── rust.txtr ├── rust_project_example ├── Cargo.lock ├── Cargo.toml ├── entry │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── lib1 │ ├── Cargo.toml │ ├── rust.txt │ ├── src │ │ ├── code.rs │ │ ├── doc.rs │ │ ├── lib.rs │ │ └── lib1_type │ │ │ ├── mod.rs │ │ │ ├── traits.rs │ │ │ └── types.rs │ └── tests │ │ └── lib1_test.rs ├── lib2 │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ └── lib2_type │ │ ├── mod.rs │ │ ├── traits.rs │ │ └── types.rs └── lib3 │ ├── Cargo.toml │ ├── example │ └── example.rs │ └── src │ ├── lib.rs │ └── lib3_type │ ├── mod.rs │ ├── traits.rs │ └── types.rs └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore 2 | target/ 3 | .idea/ -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ['module-one','module-two','module-three','module-four','module-five','module-six'] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-co-learn 2 | 3 | 克隆项目至本地 4 | 5 | ``` 6 | git clone https://github.com/CreatorsDAO/rust-co-learn 7 | ``` 8 | 9 | 使用cargo doc 打开 10 | 11 | ``` 12 | cd rust-co-learn 13 | cargo doc --no-deps --open 14 | ``` 15 | 16 | -------------------------------------------------------------------------------- /additional-references/3.2 迭代器 Iterator.md: -------------------------------------------------------------------------------- 1 | > 内容参考:[陈天《Rust 编程第一课》](https://time.geekbang.org/column/intro/100085301?tab=catalog)、[Rust 圣经](https://course.rs/advance/smart-pointer/deref.html)、《Rust Programming》 2 | 3 | 4 | 5 | 迭代器允许我们迭代一个连续的集合,例如数组、动态数组 `Vec`、`HashMap` 等,在此过程中,只需关心集合中的元素如何处理,而无需关心如何开始、如何结束、按照什么样的索引去访问等问题 6 | 7 | 8 | 9 | ### [For 循环与迭代器](https://course.rs/advance/functional-programing/iterator.html#for-%E5%BE%AA%E7%8E%AF%E4%B8%8E%E8%BF%AD%E4%BB%A3%E5%99%A8) 10 | 11 | 从用途来看,迭代器跟 `for` 循环颇为相似,都是去遍历一个集合,但是实际上它们存在不小的差别,其中最主要的差别就是:**是否通过索引来访问集合**。 12 | 13 | ```rust 14 | let arr = [1, 2, 3]; 15 | for v in arr { // `Rust`中没有使用索引,它把 `arr` 数组当成一个迭代器,直接去遍历其中的元素 16 | println!("{}",v); 17 | } 18 | ``` 19 | 20 | 在 Rust 中数组是迭代器 Iterator 吗? `No`。那既然数组不是迭代器,为啥咱可以对它的元素进行迭代呢? 21 | 22 | 23 | 24 | 简而言之就是**数组 实现了 `IntoIterator` Trait**,Rust 通过 `for` 语法糖,自动把实现了该 Trait 的数组类型转换为 `Iterator`(你也可以为自己的集合类型实现此特征),最终让我们可以直接对一个数组进行迭代,类似的还有: 25 | 26 | ```rust 27 | for i in 1..10 { // 直接对数值序列进行迭代: Rust 自动进行类型转换,将 1..10 这个 28 | println!("{}", i); // 数组转换为一个 Iterator。这是通过使用`IntoIterator` trait实现的 29 | } 30 | ``` 31 | 32 | `IntoIterator` 特征拥有一个 `into_iter` 方法,因此我们还可以显式的把数组转换成迭代器: 33 | 34 | ```rust 35 | let arr = [1, 2, 3]; 36 | for v in arr.into_iter() { 37 | println!("{}", v); } 38 | ``` 39 | 40 | 41 | 42 | 看下 `IntoIterator` 的源码: 43 | 44 | ```rust 45 | trait Iterator { 46 | type Item; 47 | fn next(&mut self) -> Option; 48 | } 49 | 50 | pub trait IntoIterator { 51 | type Item; 52 | type IntoIter: Iterator; 53 | 54 | // Required method 55 | fn into_iter(self) -> Self::IntoIter; 56 | } 57 | ``` 58 | 59 | `Iterator` trait 定义了一个关联类型 `type Item` 和一个方法 `fn next(&mut self) -> Option`。表示任何实现 `Iterator` trait 的类型都会提供一个 `Item` 类型,以及一个 `next` 方法。 `next()` 方法在调用时会返回一个 `Option` 类型的值: 60 | 61 | - `Some(Item)` 表示迭代器还有元素可以提供 62 | - `None` 表示迭代器已经没有元素了。 63 | 64 | 65 | 66 | `IntoIterator` trait 是一种将类型转换为迭代器的方法 67 | 68 | - `IntoIter` 类型表示了实现 `IntoIterator` trait 的类型可以被转换为的迭代器 `Iterator` 的类型,这个迭代器的 `Item` 类型应该和原类型的 `Item` 类型相同。`into_iter` 方法是把自身转换为一个迭代器 `Iterator`。 69 | - 任何实现了 `IntoIterator` trait 的类型,都可以被转换为一个迭代器 `Iterator`,并通过`Iterator` 的 `next` 方法获取元素,直到 `Iterator` 被耗尽。 70 | 71 | 72 | 73 | ### next() 74 | 75 | `for` 循环通过不停调用迭代器上的 `next` 方法,来获取迭代器中的元素。 来看 `Iterator` Trait : 76 | 77 | ```rust 78 | pub trait Iterator { 79 | type Item; 80 | fn next(&mut self) -> Option; 81 | } 82 | ``` 83 | 84 | 既然 `for` 可以调用 `next` 方法,我们也显式可以调用 `next()` : 85 | 86 | ```rust 87 | fn main() { 88 | let arr = [1, 2, 3]; 89 | let mut arr_iter = arr.into_iter(); 90 | 91 | assert_eq!(arr_iter.next(), Some(1)); 92 | assert_eq!(arr_iter.next(), Some(2)); 93 | assert_eq!(arr_iter.next(), Some(3)); 94 | assert_eq!(arr_iter.next(), None); 95 | } 96 | ``` 97 | 98 | 注意 : 99 | - `next` 方法返回的是 `Option` 类型,有值时返回 `Some(i32)`,无值时返回 `None` 100 | - 遍历是按照迭代器中元素的排列顺序依次进行的,因此我们严格按照数组中元素的顺序取出了 `Some(1)`,`Some(2)`,`Some(3)` 101 | - **手动迭代必须将迭代器声明为 `mut` 可变,因为调用 `next` 会改变迭代器其中的状态数据(当前遍历的位置等),而 `for` 循环去迭代则无需标注 `mut`,因为它会帮我们自动完成** 102 | 103 | `next` 方法对**迭代器的遍历是消耗性的**,每次消耗它一个元素,最终迭代器中将没有任何元素,只能返回 `None`。 104 | 105 | 106 | 107 | ### for 循环解糖 108 | 109 | ```rust 110 | fn main(){ 111 | // for 循环解糖后等价如下: 112 | let v = vec![1, 2, 3, 4, 5]; 113 | // 先将集合转为(可变)迭代器 114 | let mut v_iter = v.into_iter(); 115 | // 在 loop 循环中使用next方法循环获取集合中下一个元素,当集合中取不到值时使用 break终止 loop循环 116 | loop { 117 | match v_iter.next() { 118 | Some(x) => println!("{}", x), 119 | None => break, 120 | } 121 | } 122 | } 123 | /* 打印: 1 2 3 4 5 */ 124 | ``` 125 | 126 | 127 | 128 | ### 惰性初始化 129 | 130 | 创建了迭代器 `v1_iter` 后,他自己不会**主动发生任何迭代行为** . 131 | > 只有在 `for` 循环开始后,迭代器才会开始迭代其中的元素,最后打印出来。 这种惰性初始化的方式确保了创建迭代器不会有任何额外的性能损耗,其中的元素也不会被消耗,只有使用到该迭代器的时候,一切才刚刚开始。 132 | 133 | 134 | 135 | ### Iterator IntoIterator 区别 136 | 137 | 很容易搞混,但我们只需要记住: 138 | - **`Iterator` 就是迭代器 Trait,只有实现了它才能称为迭代器,才能调用 `next()`**。 139 | - **`IntoIterator` 强调的是某一个类型如果实现了该特征,它可以通过 `into_iter`,`iter` 等方法变成一个迭代器** 140 | 141 | 142 | 143 | ### Iterator 的借用和所有权 144 | 145 | - `into_iter` 会**夺走所有权** 146 | - `iter` 是借用 147 | - `iter_mut` 是可变借用 148 | 149 | ```rust 150 | let mut v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; 151 | let iter_mut: IterMut = v.iter_mut(); // 转为 IterMut 结构体, 可变借用 152 | let iter: Iter = v.iter(); // 转为 Iter 结构体, 不可变借用 153 | let iter_into: IntoIter = v.into_iter(); // 转为 IntoIter 结构体 , 获取所有权 154 | ``` 155 | 156 | 157 | 158 | 以后见多识广了,你会发现这种问题一眼就能看穿: 159 | 160 | - `into_xxx` 之类的,都是拿走所有权, 161 | - `xxx_mut` 之类的都是可变借用, 162 | - 剩下的就是不可变借用。 163 | 164 | 165 | 166 | ### Iterator Consumer 167 | 168 | 只要迭代器上的某个方法 `A` 在其内部调用了 `next` 方法,那么 `A` 就被称为 **Iterator Consumer(消费性适配器)**:因为 `next` 方法会消耗掉迭代器上的元素,所以方法 `A` 的调用也会消耗掉迭代器上的元素。 169 | 170 | 其中一个例子是 `sum` 方法,它会**拿走迭代器的所有权**,然后通过不断调用 `next` 方法对里面的元素进行求和: 171 | 172 | ```rust 173 | fn main() { 174 | let v1 = vec![1, 2, 3]; 175 | let v1_iter = v1.iter(); // 创建一个不可变的迭代器 176 | 177 | let total: i32 = v1_iter.sum(); 178 | 179 | assert_eq!(total, 6); 180 | 181 | // v1_iter 是借用了 v1,因此 v1 可以照常使用 182 | println!("{:?}", v1); 183 | 184 | // 以下代码会报错,因为 `sum` 拿到了迭代器 `v1_iter` 的所有权 185 | // println!("{:?}",v1_iter); ❌ Error 186 | } 187 | ``` 188 | 189 | 如上代码注释:使用 `sum` 方法后,无法再使用 `v1_iter`,因为 `sum` 拿走了该迭代器的所有权: 190 | 191 | ```rust 192 | fn sum(self) -> S // `self` 参数拿走了所有权。 193 | where 194 | Self: Sized, 195 | S: Sum, 196 | { 197 | Sum::sum(self) 198 | } 199 | ``` 200 | 201 | 202 | 203 | ### Iterator Adapters 204 | 205 | Adapters take an **iterator** and return **another iterator** 206 | `Iterator Adapters` 是实现链式方法调用的关键:`v.iter().map().filter()...`。 207 | 208 | 与消费者适配器不同,迭代器适配器是惰性的,意味着你**需要一个消费者适配器来收尾,最终将迭代器转换成一个具体的值**: 209 | 210 | 211 | 212 | #### collect 213 | 214 | ```rust 215 | let v1: Vec = vec![1, 2, 3]; 216 | let v2: Vec<_> = v1.iter().map(|x| x + 1).collect(); 217 | assert_eq!(v2, vec![2, 3, 4]); 218 | ``` 219 | 220 | `collect` 方法是一个 **Iterator Consumer(消费性适配器)**,使用它可以进行 "收尾工作": 例如将一个迭代器中的元素收集到**指定类型**中,这里我们为 `v2` 标注了 `Vec<_>` 类型 `let v2: Vec<_>` ,就是为了告诉 `collect`:请把迭代器中的元素消费掉,然后把值收集成 `Vec<_>` 类型,至于为何使用 `_` ,因为我们让编译器帮我们自动推导 `Vec` 中类型。 221 | 222 | 为何 `collect` 在消费时要指定类型?是因为该方法其实很强大,可以收集成多种不同的集合类型,`Vec` 仅仅是其中之一,因此我们必须显式的告诉编译器我们想要收集成的集合类型。 223 | 224 | 还有一点值得注意,`map` 会对迭代器中的每一个值进行一系列操作,然后把该值转换成另外一个新值,该操作是通过闭包 `|x| x + 1` 来完成:最终迭代器中的每个值都增加了 `1`,从 `[1, 2, 3]` 变为 `[2, 3, 4]`。 225 | 226 | 再来看看如何使用 `collect` 收集成 `HashMap` 集合: 227 | 228 | ```rust 229 | use std::collections::HashMap; 230 | fn main() { 231 | let names = ["sunface", "sunfei"]; 232 | let ages = [18, 18]; 233 | let folks: HashMap<_, _> = names.into_iter().zip(ages.into_iter()).collect(); 234 | 235 | println!("{:?}",folks); 236 | } 237 | ``` 238 | 239 | - `zip` 是一个迭代器适配器,它的作用就是将两个迭代器的内容压缩到一起,形成 `Iterator` 这样的新的迭代器,在此处就是形如 `[(name1, age1), (name2, age2)]` 的迭代器。 240 | - 然后再通过 `collect` 将新迭代器中`(K, V)` 形式的值收集成 `HashMap`,同样的,这里必须显式声明类型,然后 `HashMap` 内部的 `KV` 类型可以交给编译器去推导,最终编译器会推导出 `HashMap<&str, i32>`,完全正确! 241 | - `let folks: HashMap<_, _>` : HashMap 中的 2 个类型都让编译器自动推断 242 | 243 | 244 | 245 | 迭代器是 Rust 的核心特性,它赋予了 Rust 远超于循环的强大表达能力。 -------------------------------------------------------------------------------- /additional-references/assets/2022-10-31-IMG_0802.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/706creators/rust-co-learn/02a2a2141c7fcc577d410c161831138f3ec45bfb/additional-references/assets/2022-10-31-IMG_0802.jpg -------------------------------------------------------------------------------- /additional-references/assets/2022-11-23-trpl04-04.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | %3 11 | 12 | 13 | 14 | table0 15 | 16 | 17 | s1 (invalid after move) 18 | 19 | name 20 | 21 | value 22 | 23 | ptr 24 | 25 | 26 | len 27 | 28 | 5 29 | 30 | capacity 31 | 32 | 5 33 | 34 | 35 | 36 | table1 37 | 38 | index 39 | 40 | value 41 | 42 | 0 43 | 44 | h 45 | 46 | 1 47 | 48 | e 49 | 50 | 2 51 | 52 | l 53 | 54 | 3 55 | 56 | l 57 | 58 | 4 59 | 60 | o 61 | 62 | 63 | 64 | table0:c->table1:pointee 65 | 66 | 67 | 68 | 69 | 70 | table3 71 | 72 | s2 73 | 74 | name 75 | 76 | value 77 | 78 | ptr 79 | 80 | 81 | len 82 | 83 | 5 84 | 85 | capacity 86 | 87 | 5 88 | 89 | 90 | 91 | table3:c->table1:pointee 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /additional-references/assets/2023-01-12-153248.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/706creators/rust-co-learn/02a2a2141c7fcc577d410c161831138f3ec45bfb/additional-references/assets/2023-01-12-153248.png -------------------------------------------------------------------------------- /additional-references/assets/2023-02-01-082322.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/706creators/rust-co-learn/02a2a2141c7fcc577d410c161831138f3ec45bfb/additional-references/assets/2023-02-01-082322.png -------------------------------------------------------------------------------- /additional-references/assets/2023-02-01-082744.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/706creators/rust-co-learn/02a2a2141c7fcc577d410c161831138f3ec45bfb/additional-references/assets/2023-02-01-082744.png -------------------------------------------------------------------------------- /additional-references/assets/2023-06-22-024342.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/706creators/rust-co-learn/02a2a2141c7fcc577d410c161831138f3ec45bfb/additional-references/assets/2023-06-22-024342.png -------------------------------------------------------------------------------- /additional-references/assets/97a6byy90566585499eabf4feda14783.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/706creators/rust-co-learn/02a2a2141c7fcc577d410c161831138f3ec45bfb/additional-references/assets/97a6byy90566585499eabf4feda14783.jpg -------------------------------------------------------------------------------- /additional-references/assets/c1e1c1909b761cfa3348115bb417d4d4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/706creators/rust-co-learn/02a2a2141c7fcc577d410c161831138f3ec45bfb/additional-references/assets/c1e1c1909b761cfa3348115bb417d4d4.png -------------------------------------------------------------------------------- /attribute-macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "attribute-macro" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | syn = { version = "1.0", features = ["full"] } 10 | quote = "1.0" 11 | 12 | [lib] 13 | proc-macro = true -------------------------------------------------------------------------------- /attribute-macro/src/lib.rs: -------------------------------------------------------------------------------- 1 | // 导入所需库 2 | extern crate proc_macro; 3 | use proc_macro::TokenStream; 4 | use quote::quote; 5 | use syn::parse_macro_input; 6 | use syn::ItemFn; 7 | // 使用 proc_macro_attribute 属性标记属性宏,并将宏命名为 show_function_name。 8 | #[proc_macro_attribute] 9 | pub fn show_function_name(_attr: TokenStream, item: TokenStream) -> TokenStream { 10 | // 将输入的 TokenStream 解析为 ItemFn 结构体。 11 | let input_ast = parse_macro_input!(item as ItemFn); 12 | // 从 ItemFn 结构体中提取函数的名称。 13 | let name = &input_ast.sig.ident; 14 | 15 | // 使用 quote 宏构造修改后的函数代码。 16 | let func = quote! { 17 | // 重新定义函数。 18 | fn #name() { 19 | // 在函数开始时打印函数名称。 20 | println!("Function name: {}", stringify!(#name)); 21 | } 22 | }; 23 | 24 | // 将生成的代码转换为 TokenStream 并返回。 25 | func.into() 26 | } 27 | -------------------------------------------------------------------------------- /demos/blockchain-rust/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea 3 | Cargo.lock 4 | data 5 | 6 | -------------------------------------------------------------------------------- /demos/blockchain-rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "blockchain-rust" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | sha2 = "0.10.6" 10 | rust-crypto = "0.2.36" 11 | bincode = "1.3" 12 | failure = "0.1" 13 | sled = "0.34" 14 | log = "0.4" 15 | env_logger = "0.10.0" 16 | clap = "4.0.29" 17 | bitcoincash-addr = "0.5.2" 18 | rand = "0.8.5" 19 | merkle-cbt = "0.3.2" 20 | serde = {version = "1.0", features = ["derive"] } 21 | serde_json = "1.0" 22 | 23 | [workspace] 24 | 25 | -------------------------------------------------------------------------------- /demos/blockchain-rust/Merkle_Tree tx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/706creators/rust-co-learn/02a2a2141c7fcc577d410c161831138f3ec45bfb/demos/blockchain-rust/Merkle_Tree tx.png -------------------------------------------------------------------------------- /demos/blockchain-rust/merkle_tree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/706creators/rust-co-learn/02a2a2141c7fcc577d410c161831138f3ec45bfb/demos/blockchain-rust/merkle_tree.jpg -------------------------------------------------------------------------------- /demos/blockchain-rust/src/block.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | #![allow(unused)] 3 | //! Block implement of blockchain 4 | 5 | use super::*; 6 | use crate::transaction::Transaction; 7 | use bincode::serialize; 8 | use crypto::digest::Digest; 9 | use crypto::sha2::Sha256; 10 | use merkle_cbt::merkle_tree::Merge; 11 | use merkle_cbt::merkle_tree::CBMT; 12 | use serde::{Deserialize, Serialize}; 13 | use std::time::{SystemTime}; 14 | use log::info; 15 | 16 | const TARGET_HEXS: usize = 4; 17 | 18 | /// Block keeps block headers 19 | #[derive(Serialize, Deserialize, Debug, Clone)] 20 | pub struct Block { 21 | timestamp: u128, 22 | transactions: Vec, 23 | prev_block_hash: String, 24 | hash: String, // 区块哈希值可以唯一、明确地标识一个区块,并且任何节点哈希计算都可以独立地获取该区块哈希值。 25 | nonce: i32, // A counter used for the proof-of-work algorithm 26 | height: i32, 27 | // Why no Merkle Root hash ? 28 | } 29 | 30 | impl Block { 31 | pub fn get_hash(&self) -> String { 32 | self.hash.clone() 33 | } 34 | 35 | pub fn get_prev_hash(&self) -> String { 36 | self.prev_block_hash.clone() 37 | } 38 | 39 | pub fn get_transaction(&self) -> &Vec { 40 | &self.transactions 41 | } 42 | 43 | pub fn get_height(&self) -> i32 { 44 | self.height 45 | } 46 | 47 | /// NewBlock creates and returns Block 48 | pub fn new_block( 49 | transactions: Vec, 50 | prev_block_hash: String, 51 | height: i32, 52 | ) -> Result { 53 | let timestamp = SystemTime::now() 54 | .duration_since(SystemTime::UNIX_EPOCH)? // UNIX_EPOCH 获取当前系统时间, 计算当前时间距离UNIX纪元的Duration 55 | .as_millis(); // 转化为毫秒数 56 | let mut block = Block { 57 | timestamp, 58 | transactions, 59 | prev_block_hash, 60 | hash: String::new(), 61 | nonce: 0, 62 | height, 63 | }; 64 | block.run_proof_of_work()?; // 不断循环, 直到挖到为止 65 | Ok(block) 66 | } 67 | 68 | /// NewGenesisBlock creates and returns genesis Block 69 | pub fn new_genesis_block(coinbase: Transaction) -> Block { 70 | // coinbase = Transaction::new_coinbase(address, String::from(GENESIS_COINBASE_DATA))?; 71 | Block::new_block(vec![coinbase], String::new(), 0).unwrap() 72 | } 73 | 74 | /// Run performs a proof-of-work 75 | /// 矿工可以通过不断改变区块的 nonce 值 (随机数), 来寻找满足条件的哈希值, 这是实现工作量证明算法的关键步骤 76 | /// 挖矿: 不断地改变 block.nonce 的值(+= 1),直到找到一个使 validate 方法返回 true 的 nonce 77 | /// 只要调用这个函数, 就会不断循环, 直到挖到合适的 nonce 才停止. 78 | fn run_proof_of_work(&mut self) -> Result<()> { 79 | info!("Mining the block"); 80 | while !self.validate()? { 81 | self.nonce += 1; // 不断改变 Block 的 nonce 82 | } 83 | let data = self.prepare_hash_data()?; // 运行到这里, 说明找到了符合条件的 nonce. 84 | let mut hasher = Sha256::new(); 85 | hasher.input(&data[..]); 86 | self.hash = hasher.result_str(); 87 | Ok(()) 88 | } 89 | 90 | /// HashTransactions returns a hash of the transactions in the block 91 | /// 将区块中的所有交易哈希化,然后用 Merkle 树组合这些哈希值,得到一个树根,这个树根是一个对区块中所有交易的摘要 92 | fn hash_transactions(&self) -> Result> { 93 | let mut transactions = Vec::new(); 94 | for tx in &self.transactions { 95 | transactions.push(tx.hash()?.as_bytes().to_owned()); 96 | } 97 | let tree = CBMT::, MergeVu8>::build_merkle_tree(&transactions); 98 | 99 | Ok(tree.root()) 100 | } 101 | 102 | /// 将 { 上一个区块 hash, 挖到的符合条件的 nonce, 时间戳, 交易数据} 等结构化数据序列化成字节流 Vec 返回. 103 | /// 这一步是为了将目前的 Block 的数据整体做 hash() ,作为未来下一个区块中的 "Previous Block hash" 字段的内容. 104 | fn prepare_hash_data(&self) -> Result> { 105 | let content = ( 106 | self.prev_block_hash.clone(), 107 | self.hash_transactions()?, // tree.root's hash 108 | self.timestamp, 109 | TARGET_HEXS, // 4 110 | self.nonce, 111 | ); 112 | let bytes = serialize(&content)?; 113 | Ok(bytes) 114 | } 115 | 116 | /// Validate validates block's PoW 117 | /// 本 Block 的 nonce 不断变化, 不断调用该函数验证该 nonce 是否能让区块的哈希值满足某种条件 (hash 完后 TARGET_HEXS 位为 0) 118 | fn validate(&self) -> Result { 119 | let data = self.prepare_hash_data()?; // hash(Block) 120 | let mut hasher = Sha256::new(); 121 | hasher.input(&data[..]); 122 | let mut vec1: Vec = Vec::new(); 123 | // println!("{:?}", vec1): [48, 48, 48, 48] , 48 是 '0' 的编码结果(utf-8), 这里挖矿难度是固定的, 最后 4 位 0 124 | vec1.resize(TARGET_HEXS, '0' as u8); 125 | // 比较哈希值的前 TARGET_HEXS (4) 位和全零向量是否相等,如果相等,就说明 nonce 有效。 126 | Ok(&hasher.result_str()[0..TARGET_HEXS] == String::from_utf8(vec1)?) 127 | } 128 | } 129 | 130 | struct MergeVu8 {} // MergeVu8 struct 只是一个实现特定功能的载体 131 | 132 | /// 接收两个 Vec 类型的引用,将它们合并后,用 SHA256 生成 hash value 133 | impl Merge for MergeVu8 { 134 | type Item = Vec; // 本实现中, 我们处理的数据类型是 Vec 135 | fn merge(left: &Self::Item, right: &Self::Item) -> Self::Item { 136 | let mut re: [u8; 32] = [0; 32]; 137 | 138 | let mut hasher = Sha256::new(); 139 | let mut data: Vec = left.clone(); 140 | data.append(&mut right.clone()); 141 | hasher.input(&data); 142 | hasher.result(&mut re); // 将 hash 结果吐到 re 中 143 | re.to_vec() // 是否可以不用辅助变量 re, 直接使用 into_bytes 将 String 转化为 Vec bytes ? 144 | // hasher.result_str().into_bytes() 145 | } 146 | } -------------------------------------------------------------------------------- /demos/blockchain-rust/src/blockchain.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | #![allow(unused)] 3 | //! Blockchain 4 | 5 | use super::*; 6 | use crate::block::*; 7 | use crate::transaction::*; 8 | use bincode::{deserialize, serialize}; 9 | use failure::format_err; 10 | use log::{debug, info}; 11 | use serde_json::map::IterMut; 12 | use sled; 13 | use std::collections::HashMap; 14 | 15 | // 这是当时《泰晤士报》的一条新闻标题,用来证明这个区块是在2009年1月3日之后创建的 16 | // 在比特币网络中,创世区块在2009年由中本聪(Satoshi)创建,并且从那时起就固定在比特币区块链的开始处. 17 | const GENESIS_COINBASE_DATA: &str = 18 | "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"; 19 | 20 | /// Blockchain implements interactions with a DB 21 | #[derive(Debug)] 22 | pub struct Blockchain { 23 | // 字段前的 pub: 即使 Blockchain 已经声明 pub, 如果字段 tip/db 不声明, 也仍是默认私有的.. 24 | pub tip: String, // 存放 lasthash 即最后一个区块的哈希, 25 | pub db: sled::Db, // 区块链 db 中的每一个区块都是通过其哈希来索引的,同时 db 上还有一个特殊的 key "LAST" 用来存储最后一个区块的哈希 26 | } 27 | 28 | /// BlockchainIterator is used to iterate over blockchain blocks 遍历区块链 29 | pub struct BlockchainIterator<'a> { 30 | current_hash: String, 31 | bc: &'a Blockchain, // bc 是指向 Blockchain 的引用, lifetime 标注告诉编译器: 引用的有效期至少和 'a 一样长 32 | } 33 | 34 | impl Blockchain { 35 | /// NewBlockchain creates a new Blockchain db 36 | pub fn new() -> Result { 37 | info!("open blockchain"); 38 | 39 | let db = sled::open("data/blocks")?; 40 | let hash = match db.get("LAST")? { 41 | Some(l) => l.to_vec(), 42 | None => Vec::new(), 43 | }; 44 | 45 | let lasthash = if hash.is_empty() { 46 | info!("Create block database"); // no key "LAST" 47 | String::new() 48 | } else { 49 | info!("Found block database"); 50 | String::from_utf8(hash.to_vec())? 51 | }; 52 | Ok(Blockchain { tip: lasthash, db }) 53 | } 54 | 55 | /// CreateBlockchain creates a new blockchain DB 56 | /// 化身中本聪, 创建比特币区块链! 第一步: 创建创始区块! 57 | /// 先清空本地数据库,创建一个新的 db 文件,并添加一个创世区块,该区块包含一个 coinbase 交易 (cbtx) 58 | pub fn create_blockchain(address: String) -> Result { 59 | info!("Creating new blockchain"); 60 | 61 | std::fs::remove_dir_all("data/blocks").ok(); 62 | let db = sled::open("data/blocks")?; 63 | debug!("Creating new block database"); 64 | // GENESIS_COINBASE_DATA: 这是当时《泰晤士报》的一条新闻标题,用来证明这个区块是在2009年1月3日之后创建的 65 | // 在比特币网络中,创世区块在2009年由中本聪(Satoshi)创建,并且从那时起就固定在比特币区块链的开始处. 66 | let cbtx = Transaction::new_coinbase(address, String::from(GENESIS_COINBASE_DATA))?; 67 | let genesis: Block = Block::new_genesis_block(cbtx); //化身中本聪, 创建创始区块! 68 | db.insert(genesis.get_hash(), serialize(&genesis)?)?; 69 | db.insert("LAST", genesis.get_hash().as_bytes())?; 70 | let bc = Blockchain { 71 | tip: genesis.get_hash(), 72 | db, 73 | }; 74 | bc.db.flush()?; 75 | Ok(bc) 76 | } 77 | 78 | /// MineBlock mines a new block with the provided transactions 79 | /// 挖掘一个新的区块 —— 调用 new_block 调用 run_proof_of_work 不断循环, 直到挖到合适的 nonce 80 | pub fn mine_block(&mut self, transactions: Vec) -> Result { 81 | info!("mine a new block"); 82 | 83 | for tx in &transactions { 84 | // 循环验证所有交易的有效性 85 | if !self.verify_transacton(tx)? { 86 | return Err(format_err!("ERROR: Invalid transaction")); 87 | } 88 | } 89 | 90 | let lasthash = self.db.get("LAST")?.unwrap(); 91 | 92 | /// while 不断循环, 直到挖到合适的 nonce 为止 93 | let newblock = Block::new_block( 94 | transactions, 95 | String::from_utf8(lasthash.to_vec())?, // 将 'LAST' Block 作为 Prev 96 | self.get_best_height()? + 1, 97 | )?; 98 | self.db.insert(newblock.get_hash(), serialize(&newblock)?)?; 99 | self.db.insert("LAST", newblock.get_hash().as_bytes())?; 100 | self.db.flush()?; 101 | 102 | self.tip = newblock.get_hash(); // tip 字段: 最后一个区块的哈希,让它指向新的区块 103 | Ok(newblock) 104 | } 105 | 106 | /// 为 Blockchain 定义 iter() 方法, 辅助后面 Iterator 的实现. 107 | /// ps: Blockchain 没实现 Iterator trait,但它通过实现这个 iter() 方法 returns BlockchainIterator 迭代器对象。 108 | /// BlockchainIterator 迭代器对象实现了Iterator trait,因此可以在 for 循环中使用。 109 | pub fn iter(&self) -> BlockchainIterator { 110 | BlockchainIterator { 111 | current_hash: self.tip.clone(), 112 | bc: &self, 113 | } 114 | } 115 | 116 | /// FindUTXO finds and returns all unspent transaction outputs 117 | pub fn find_UTXO(&self) -> HashMap { 118 | let mut utxos: HashMap = HashMap::new(); // 存储了所有未花费的交易输出 119 | let mut spend_txos: HashMap> = HashMap::new(); // 存储了所有已经花费的输出 120 | 121 | // 迭代 整个区块链 db 的每个区块 & 每个区块中的每个交易 122 | for block in self.iter() { 123 | // Blockchain 没实现 Iterator, 但是其 iter() 方法返回了 BlockchainIterator 124 | for tx in block.get_transaction() { 125 | // 对于交易的每个输出,我们检查它是否在 spend_txos 中,如果在,则表示这个输出已经被花费, 126 | // 我们跳过这个输出。否则,我们将这个输出添加到 utxos 中。 127 | // 这样,当我们处理完所有区块和所有交易后,utxos 中就存储了所有的 UTXOs。 128 | for index in 0..tx.vout.len() { 129 | if let Some(ids) = spend_txos.get(&tx.id) { 130 | if ids.contains(&(index as i32)) { 131 | continue; 132 | } 133 | } 134 | 135 | match utxos.get_mut(&tx.id) { 136 | Some(v) => { 137 | v.outputs.push(tx.vout[index].clone()); 138 | } 139 | None => { 140 | utxos.insert( 141 | tx.id.clone(), 142 | TXOutputs { 143 | outputs: vec![tx.vout[index].clone()], 144 | }, 145 | ); 146 | } 147 | } 148 | } 149 | 150 | if !tx.is_coinbase() { 151 | for i in &tx.vin { 152 | match spend_txos.get_mut(&i.txid) { 153 | Some(v) => { 154 | v.push(i.vout); 155 | } 156 | None => { 157 | spend_txos.insert(i.txid.clone(), vec![i.vout]); 158 | } 159 | } 160 | } 161 | } 162 | } 163 | } 164 | 165 | utxos 166 | } 167 | 168 | /// FindTransaction finds a transaction by its ID 169 | pub fn find_transacton(&self, id: &str) -> Result { 170 | for b in self.iter() { 171 | for tx in b.get_transaction() { 172 | if tx.id == id { 173 | return Ok(tx.clone()); 174 | } 175 | } 176 | } 177 | Err(format_err!("Transaction is not found")) 178 | } 179 | 180 | fn get_prev_TXs(&self, tx: &Transaction) -> Result> { 181 | let mut prev_TXs = HashMap::new(); 182 | for vin in &tx.vin { 183 | let prev_TX = self.find_transacton(&vin.txid)?; 184 | prev_TXs.insert(prev_TX.id.clone(), prev_TX); 185 | } 186 | Ok(prev_TXs) 187 | } 188 | 189 | /// SignTransaction signs inputs of a Transaction 190 | pub fn sign_transacton(&self, tx: &mut Transaction, private_key: &[u8]) -> Result<()> { 191 | let prev_TXs = self.get_prev_TXs(tx)?; 192 | tx.sign(private_key, prev_TXs)?; 193 | Ok(()) 194 | } 195 | 196 | /// VerifyTransaction verifies transaction input signatures 197 | pub fn verify_transacton(&self, tx: &Transaction) -> Result { 198 | if tx.is_coinbase() { 199 | return Ok(true); 200 | } 201 | let prev_TXs = self.get_prev_TXs(tx)?; 202 | tx.verify(prev_TXs) 203 | } 204 | 205 | /// AddBlock saves the block into the blockchain 206 | /// mine_block 对应的是挖矿过程, 这个 add_block 接收一个 block 并将其添加到 Blockchain 207 | pub fn add_block(&mut self, block: Block) -> Result<()> { 208 | let data = serialize(&block)?; 209 | if let Some(_) = self.db.get(block.get_hash())? { 210 | return Ok(()); 211 | } 212 | self.db.insert(block.get_hash(), data)?; 213 | 214 | let lastheight = self.get_best_height()?; 215 | if block.get_height() > lastheight { 216 | self.db.insert("LAST", block.get_hash().as_bytes())?; 217 | self.tip = block.get_hash(); 218 | self.db.flush()?; 219 | } 220 | Ok(()) 221 | } 222 | 223 | // GetBlock finds a block by its hash and returns it 224 | pub fn get_block(&self, block_hash: &str) -> Result { 225 | let data = self.db.get(block_hash)?.unwrap(); 226 | let block = deserialize(&data.to_vec())?; 227 | Ok(block) 228 | } 229 | 230 | /// GetBestHeight returns the height of the latest block 231 | pub fn get_best_height(&self) -> Result { 232 | let lasthash = if let Some(h) = self.db.get("LAST")? { 233 | h 234 | } else { 235 | return Ok(-1); 236 | }; 237 | let last_data = self.db.get(lasthash)?.unwrap(); 238 | let last_block: Block = deserialize(&last_data.to_vec())?; 239 | Ok(last_block.get_height()) 240 | } 241 | 242 | /// GetBlockHashes returns a list of hashes of all the blocks in the chain 243 | pub fn get_block_hashs(&self) -> Vec { 244 | let mut list = Vec::new(); 245 | for b in self.iter() { 246 | list.push(b.get_hash()); 247 | } 248 | list 249 | } 250 | } 251 | 252 | /// 为 BlockchainIterator 实现了 Iterator trait! 253 | /// if let: 如果获取成功(即返回 Ok(encoded_block)),那么 encoded_block 就会被解包并赋值 254 | /// return match: 返回匹配到的分支 255 | /// Option: next() 方法需要返回一个 Option 类型, Option 里包裹着 Block 256 | impl<'a> Iterator for BlockchainIterator<'a> { 257 | type Item = Block; 258 | 259 | fn next(&mut self) -> Option { 260 | if let Ok(encoded_block) = self.bc.db.get(&self.current_hash) { 261 | return match encoded_block { 262 | Some(b) => { 263 | if let Ok(block) = deserialize::(&b) { 264 | self.current_hash = block.get_prev_hash(); 265 | Some(block) 266 | } else { 267 | None 268 | } 269 | } 270 | None => None, 271 | }; 272 | } 273 | None 274 | } 275 | } 276 | 277 | use super::*; 278 | 279 | #[test] 280 | fn test_add_block() { 281 | let mut b = Blockchain::new().unwrap(); 282 | // b.add_block("data1".to_string()); 283 | // b.add_block("data2".to_string()); 284 | // b.add_block("data3".to_string()); 285 | 286 | // for item in b.iter(){ 287 | // println!("item: {:?}", item); 288 | // } 289 | } 290 | -------------------------------------------------------------------------------- /demos/blockchain-rust/src/cli.rs: -------------------------------------------------------------------------------- 1 | #![allow(warnings)] 2 | #![allow(non_snake_case)] 3 | #![allow(unused)] 4 | use std::process::exit; 5 | use bitcoincash_addr::Address; 6 | use clap::{arg, Command}; 7 | use crate::blockchain::Blockchain; 8 | use crate::errors::Result; 9 | use crate::server::Server; 10 | use crate::transaction::Transaction; 11 | use crate::utxoset::UTXOSet; 12 | use crate::wallets::{Wallet, Wallets}; 13 | 14 | pub struct Cli {} 15 | 16 | impl Cli { 17 | pub fn new() -> Result { 18 | Ok(Cli {}) 19 | } 20 | // 每一个 subcommand 对应一个可能的命令,比如 "printchain","createwallet","listaddresses" 等等 21 | pub fn run(&mut self) -> Result<()> { 22 | let matches = Command::new("blockchain-rust-demo") 23 | .version("0.1") 24 | .author("behrouz.r.fa@gmail.com") 25 | .about("blockchain in rust: a simple blockchain for learning") 26 | .subcommand(Command::new("printchain").about("print all the chain blocks")) 27 | .subcommand(Command::new("createwallet").about("create a wallet")) 28 | .subcommand(Command::new("listaddresses").about("list all addresses")) 29 | .subcommand(Command::new("reindex").about("reindex UTXO")) 30 | .subcommand(Command::new("getbalance") 31 | .about("get balance in the blochain") 32 | .arg(arg!(
"'The Address it get balance for'")) 33 | ).subcommand(Command::new("startnode") 34 | .about("start the node server") 35 | .arg(arg!("'the port server bind to locally'")) 36 | ) 37 | .subcommand(Command::new("createblockchain").about("Create new blochain") 38 | .arg(arg!(
"'The address to send gensis block reqward to' ")) 39 | ) 40 | 41 | .subcommand( 42 | Command::new("send") 43 | .about("send in the blockchain") 44 | .arg(arg!(" 'Source wallet address'")) 45 | .arg(arg!(" 'Destination wallet address'")) 46 | .arg(arg!(" 'Destination wallet address'")) 47 | .arg(arg!(-m --mine " 'the from address mine immediately'")), 48 | ) 49 | .subcommand( 50 | Command::new("startminer") 51 | .about("start the minner server") 52 | .arg(arg!(" 'the port server bind to locally'")) 53 | .arg(arg!(
" 'wallet address'")), 54 | 55 | ) 56 | .get_matches(); 57 | 58 | /// 根据 matches 的结果,调用不同的函数执行相应的命令 59 | if let Some(ref matches) = matches.subcommand_matches("startminer") { 60 | let port = if let Some(port) = matches.get_one::("PORT") { 61 | port 62 | } else { 63 | println!("PORT not supply!: usage"); 64 | exit(1) 65 | }; 66 | 67 | let address = if let Some(address) = matches.get_one::("ADDRESS") { 68 | address 69 | } else { 70 | println!("ADDRESS not supply!: usage"); 71 | exit(1) 72 | }; 73 | let bc = Blockchain::new()?; 74 | let utxo_set = UTXOSet { blockchain: bc }; 75 | let server = Server::new(port, address, utxo_set)?; 76 | server.start_server()?; 77 | } 78 | 79 | 80 | if let Some(ref matches) = matches.subcommand_matches("startnode") { 81 | if let Some(port) = matches.get_one::("PORT") { 82 | let bc = Blockchain::new()?; 83 | let utxo_set = UTXOSet { blockchain: bc }; 84 | let server = Server::new(port, "", utxo_set)?; 85 | server.start_server()?; 86 | } 87 | } 88 | 89 | if let Some(_) = matches.subcommand_matches("createwallet") { 90 | println!("address: {}", cmd_create_wallet()?); 91 | } 92 | 93 | if let Some(_) = matches.subcommand_matches("reindex") { 94 | let count = cmd_reindex()?; 95 | println!("Done! There are {} transactions in the UTXO set.", count); 96 | } 97 | 98 | if let Some(_) = matches.subcommand_matches("listaddresses") { 99 | cmd_list_address()?; 100 | } 101 | 102 | if let Some(ref matches) = matches.subcommand_matches("createblockchain") { 103 | if let Some(address) = matches.get_one::("ADDRESS") { 104 | cmd_create_blockchain(address)?; 105 | } 106 | } 107 | 108 | if let Some(ref matches) = matches.subcommand_matches("getbalance") { 109 | if let Some(address) = matches.get_one::("ADDRESS") { 110 | let balance = cmd_get_balance(address)?; 111 | println!("Balance: {}\n", balance); 112 | } 113 | } 114 | 115 | if let Some(ref matches) = matches.subcommand_matches("send") { 116 | let from = if let Some(address) = matches.get_one::("FROM") { 117 | address 118 | } else { 119 | println!("from not supply!: usage"); 120 | exit(1) 121 | }; 122 | 123 | let to = if let Some(address) = matches.get_one::("TO") { 124 | address 125 | } else { 126 | println!("from not supply!: usage"); 127 | exit(1) 128 | }; 129 | 130 | let amount: i32 = if let Some(amount) = matches.get_one::("AMOUNT") { 131 | amount.parse()? 132 | } else { 133 | println!("from not supply!: usage"); 134 | exit(1) 135 | }; 136 | 137 | if matches.contains_id("mine") { 138 | cmd_send(from, to, amount, true)?; 139 | } else { 140 | cmd_send(from, to, amount, false)?; 141 | } 142 | 143 | 144 | /*else { 145 | println!("Not printing testing lists..."); 146 | }*/ 147 | } 148 | 149 | if let Some(_) = matches.subcommand_matches("printchain") { 150 | cmd_print_chain()?; 151 | } 152 | 153 | Ok(()) 154 | } 155 | } 156 | 157 | /// mine_now变量用于控制是否立即开采一个新的区块来包含这笔交易。 158 | /// mine_now: 159 | /// true: 选择自己打包交易, 那么就需要自己 mine_block 进行挖矿 160 | /// false: `Server::send_transaction` 将交易发送到其他节点。这个交易会被添加到内存池中,等待其他矿工再其挖矿过程中将其打包进新的区块。 161 | fn cmd_send(from: &str, to: &str, amount: i32, mine_now: bool) -> Result<()> { 162 | let bc = Blockchain::new()?; // 读取本地数据库, return Blockchain { tip: lasthash, db } 163 | let mut utxo_set = UTXOSet { blockchain: bc }; 164 | let wallets = Wallets::new()?; // 读取本地数据库, return `mut wlt` obj 165 | let wallet = wallets.get_wallet(from).unwrap(); 166 | let tx = Transaction::new_UTXO(wallet, to, amount, &utxo_set)?; 167 | if mine_now { 168 | let cbtx = Transaction::new_coinbase(from.to_string(), String::from("reward!"))?; 169 | let new_block = utxo_set.blockchain.mine_block(vec![cbtx, tx])?; 170 | 171 | utxo_set.update(&new_block)?; 172 | } else { 173 | Server::send_transaction(&tx, utxo_set)?; 174 | } 175 | 176 | println!("success!"); 177 | Ok(()) 178 | } 179 | 180 | fn cmd_create_wallet() -> Result { 181 | let mut ws = Wallets::new()?; // Wallets 是钱包集合 182 | let address = ws.create_wallet(); 183 | ws.save_all()?; 184 | Ok(address) 185 | } 186 | 187 | fn cmd_reindex() -> Result { 188 | let bc = Blockchain::new()?; 189 | let utxo_set = UTXOSet { blockchain: bc }; 190 | utxo_set.reindex()?; 191 | utxo_set.count_transactions() 192 | } 193 | 194 | fn cmd_create_blockchain(address: &str) -> Result<()> { 195 | let address = String::from(address); 196 | let bc = Blockchain::create_blockchain(address)?; 197 | 198 | let utxo_set = UTXOSet { blockchain: bc }; 199 | utxo_set.reindex()?; 200 | println!("create blockchain"); 201 | Ok(()) 202 | } 203 | 204 | fn cmd_get_balance(address: &str) -> Result { 205 | let pub_key_hash = Address::decode(address).unwrap().body; 206 | let bc = Blockchain::new()?; 207 | let utxo_set = UTXOSet { blockchain: bc }; 208 | let utxos = utxo_set.find_UTXO(&pub_key_hash)?; 209 | 210 | let mut balance = 0; 211 | for out in utxos.outputs { 212 | balance += out.value; 213 | } 214 | Ok(balance) 215 | } 216 | 217 | fn cmd_print_chain() -> Result<()> { 218 | let bc = Blockchain::new()?; 219 | for b in bc.iter() { 220 | println!("{:#?}", b); 221 | } 222 | Ok(()) 223 | } 224 | 225 | fn cmd_list_address() -> Result<()> { 226 | let ws = Wallets::new()?; 227 | let addresses = ws.get_all_addresses(); 228 | println!("addresses: "); 229 | for ad in addresses { 230 | println!("{}", ad); 231 | } 232 | Ok(()) 233 | } -------------------------------------------------------------------------------- /demos/blockchain-rust/src/errors.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | pub type Result = std::result::Result; 4 | -------------------------------------------------------------------------------- /demos/blockchain-rust/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(warnings)] 2 | use crate::cli::Cli; 3 | use crate::errors::Result; 4 | 5 | mod block; 6 | 7 | mod errors; 8 | mod blockchain; 9 | mod cli; 10 | mod transaction; 11 | mod wallets; 12 | mod utxoset; 13 | mod server; 14 | 15 | /// 入口点 main 函数 16 | fn main() -> Result<()> { 17 | let mut cli = Cli::new()?; 18 | cli.run()?; 19 | 20 | Ok(()) 21 | 22 | } -------------------------------------------------------------------------------- /demos/blockchain-rust/src/transaction.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | #![allow(unused)] 3 | //! transaction implement 4 | 5 | use super::*; 6 | use crate::utxoset::*; 7 | use crate::wallets::*; 8 | use bincode::serialize; 9 | use bitcoincash_addr::Address; 10 | use crypto::digest::Digest; 11 | use crypto::ed25519; 12 | use crypto::sha2::Sha256; 13 | use failure::format_err; 14 | use rand::{Rng, RngCore}; 15 | use serde::{Deserialize, Serialize}; 16 | use std::collections::HashMap; 17 | use log::{debug, error, info}; 18 | use rand::rngs::OsRng; 19 | 20 | const SUBSIDY: i32 = 10; 21 | 22 | /// TXInput represents a transaction input 23 | #[derive(Serialize, Deserialize, Debug, Clone)] 24 | pub struct TXInput { 25 | pub txid: String, 26 | pub vout: i32, // index 序号, -1 表示 coinbase tx, cbtx 27 | pub signature: Vec, // 签名, 其他人可以通过 Alice 的 pub_key 和 整个消息体, 来验证 Alice 的 Signature 是否有效. 28 | pub pub_key: Vec, // 消费者即 Alice 的公钥 29 | } 30 | 31 | /// TXOutput represents a transaction output 32 | #[derive(Serialize, Deserialize, Debug, Clone)] 33 | pub struct TXOutput { 34 | pub value: i32, // 金额 amount 35 | pub pub_key_hash: Vec, // 标识了谁能花费这笔 TXOutput 36 | } 37 | 38 | // TXOutputs collects TXOutput 39 | #[derive(Serialize, Deserialize, Debug, Clone)] 40 | pub struct TXOutputs { 41 | pub outputs: Vec, // UTXOs 集合 42 | } 43 | 44 | /// Transaction represents a Bitcoin transaction 45 | #[derive(Serialize, Deserialize, Debug, Clone)] 46 | pub struct Transaction { 47 | pub id: String, 48 | pub vin: Vec, 49 | pub vout: Vec, 50 | } 51 | 52 | impl Transaction { 53 | /// NewUTXOTransaction creates a new transaction 54 | /// 它从一个给定的钱包创建一个新的 UTXO(未消费的交易输出)交易,发送指定数量的资金到指定的地址,并返回创建的交易 55 | pub fn new_UTXO(wallet: &Wallet, to: &str, amount: i32, utxo: &UTXOSet) -> Result { 56 | info!( 57 | "new UTXO Transaction from: {} to: {}", 58 | wallet.get_address(), to 59 | ); 60 | let mut vin = Vec::new(); 61 | 62 | // 复制钱包的公钥后, 创建公钥哈希 63 | let mut pub_key_hash = wallet.public_key.clone(); 64 | hash_pub_key(&mut pub_key_hash); 65 | 66 | // 在该公钥地址的 UTXO 集合中迭代累计查找可用于此交易的 TXOutput 。返回一个包含总额和刚刚好覆盖该笔交易的映射的元组。 67 | // ↑ 上面说的不太好懂, 举个例子: 某笔交易需要 10 BTC 68 | // 遍历 msg.sender 的 UTXO outputs, 第一笔 3 BTC,第二笔 5 BTC, 第三笔 4 BTC,此时 3+5+4=12 刚刚好也是第一次 < 10 69 | // 这 3 笔 TXOutputs 就会用来全部花费掉以执行本次交易: 转给 receiver 10 BTC ; 转给 msg.sender 2 BTC. 70 | let acc_v = utxo.find_spendable_outputs(&pub_key_hash, amount)?; 71 | 72 | // 如果交易金额 > 找到所有总额,则记录 Not Enough balance 错误并返回错误。 73 | if acc_v.0 < amount { 74 | error!("Not Enough balance"); 75 | return Err(format_err!( 76 | "Not Enough balance: current balance {}", 77 | acc_v.0 78 | )); 79 | } 80 | 81 | // 对于每个待被花费的 TXOutput 和其对应的输出索引,创建一个新的 TXInput(交易输入) 并将其添加到交易输入列表中。 82 | for tx in acc_v.1 { 83 | for out in tx.1 { // 迭代 Vec 84 | let input = TXInput { 85 | txid: tx.0.clone(), 86 | vout: out, 87 | signature: Vec::new(), 88 | pub_key: wallet.public_key.clone(), 89 | }; 90 | vin.push(input); 91 | } 92 | } 93 | 94 | // 创建交易输出: 95 | // 首先,创建一个新的交易输出,其金额等于交易金额,收款人是目标地址。 96 | // 如果找到的总额大于交易金额(意味着需要找零),则创建一个新的交易输出,其金额等于找到的总额减去交易金额,收款人是发送者的地址。 97 | let mut tx_outs = vec![TXOutput::new(amount, to.to_string())?]; 98 | if acc_v.0 > amount { // 需要找零给自己 99 | tx_outs.push(TXOutput::new(acc_v.0 - amount, wallet.get_address())?) 100 | } 101 | 102 | // 创建新的交易,其中包括已创建的交易输入和输出,然后计算并设置交易ID, 103 | let mut tx = Transaction { 104 | id: String::new(), 105 | vin, 106 | vout: tx_outs, 107 | }; 108 | tx.id = tx.hash()?; 109 | utxo.blockchain 110 | .sign_transacton(&mut tx, &wallet.secret_key)?; // 最后对交易进行签名。 111 | Ok(tx) 112 | } 113 | 114 | /// NewCoinbaseTX creates a new coinbase transaction 115 | /// CoinbaseTX 不需要通过挖矿来创建。实际上,coinbase 交易就是矿工因成功挖掘出新的区块而得到的奖励,这个奖励直接发给矿工,而不是从其他交易中取得 116 | pub fn new_coinbase(to: String, mut data: String) -> Result { 117 | info!("new coinbase Transaction to: {}", to); 118 | let mut key: [u8; 32] = [0; 32]; 119 | if data.is_empty() { 120 | let mut rand = OsRng::default(); 121 | rand.fill_bytes(&mut key); 122 | data = format!("Reward to '{}'", to); // 挖矿奖励 123 | } 124 | let mut pub_key = Vec::from(data.as_bytes()); 125 | pub_key.append(&mut Vec::from(key)); 126 | 127 | let mut tx = Transaction { 128 | id: String::new(), 129 | vin: vec![TXInput { 130 | txid: String::new(), 131 | vout: -1, 132 | signature: Vec::new(), 133 | pub_key, 134 | }], 135 | vout: vec![TXOutput::new(SUBSIDY, to)?], // 10 个 BTC 津贴作为 mine Reward. 136 | }; 137 | tx.id = tx.hash()?; 138 | Ok(tx) 139 | } 140 | 141 | /// IsCoinbase checks whether the transaction is coinbase 142 | pub fn is_coinbase(&self) -> bool { 143 | self.vin.len() == 1 && self.vin[0].txid.is_empty() && self.vin[0].vout == -1 144 | } 145 | 146 | /// Verify verifies signatures of Transaction inputs 147 | /// 验证交易输入的签名, 它将当前交易中的每个输入和先前交易相关联,并确认 `输入的签名与先前交易的输出一致` 148 | pub fn verify(&self, prev_TXs: HashMap) -> Result { 149 | if self.is_coinbase() { 150 | return Ok(true); // 它没有先前的输入,因此可以立即确认签名是有效的。 151 | } 152 | 153 | // 检查该输入是否有一个有效的相关联的先前交易 154 | for vin in &self.vin { 155 | if prev_TXs.get(&vin.txid).unwrap().id.is_empty() { 156 | return Err(format_err!("ERROR: Previous transaction is not correct")); 157 | } 158 | } 159 | 160 | // 创建当前交易的一个“修剪版”副本,它移除了输入的签名和公钥,以便我们可以重新计算它的哈希值 161 | let mut tx_copy = self.trim_copy(); 162 | 163 | for in_id in 0..self.vin.len() { 164 | let prev_Tx = prev_TXs.get(&self.vin[in_id].txid).unwrap(); // 找到该输入对应的先前的交易 165 | tx_copy.vin[in_id].signature.clear(); // 清除修剪版交易副本中此输入的签名 166 | tx_copy.vin[in_id].pub_key = prev_Tx.vout[self.vin[in_id].vout as usize] 167 | .pub_key_hash 168 | .clone(); // 将此输入在修剪版交易副本中的公钥替换为先前交易对应输出的公钥哈希。 169 | tx_copy.id = tx_copy.hash()?; // 计算修剪版交易副本的新哈希值 170 | tx_copy.vin[in_id].pub_key = Vec::new(); // 清除修剪版交易副本中此输入的公钥 171 | 172 | // 使用Ed25519签名方案验证原始交易中此输入的签名。如果签名无效,返回Ok(false),表示交易验证失败。 173 | // fn sign() 中提到: &tx_copy.id = tx_copy.hash()?, 是消息体的 hash 值. 174 | // 利用 Alice 的公钥 和 整个消息体, 我们可以验证 Alice 的 Signature 是否有效. 175 | if !ed25519::verify( 176 | &tx_copy.id.as_bytes(), 177 | &self.vin[in_id].pub_key, 178 | &self.vin[in_id].signature, 179 | ) { 180 | return Ok(false); 181 | } 182 | } 183 | // 检查了所有输入并且它们的签名都有效,那么我们返回Ok(true),表示交易验证成功。 184 | Ok(true) 185 | } 186 | 187 | /// Sign signs each input of a Transaction 188 | /// 使用私钥签名交易 (在 new_UTXO() 里调用 sign_transacton 调用 本函数. (sign_transacton 在 blockchain.rs 中)) 189 | /// 为什么要创建 copy? 计算整个交易的哈希, 如果我们直接在原始交易上操作,就需要临时清空或修改输入中的 signature 和 pub_key 字段,然后进行哈希运算。这样做会修改原始交易,而我们并不希望这样。 190 | /// 交易中的重要信息都需要被包含进去做 hash, 这样,如果交易中的任何部分发生改变,哈希值就会改变,导致签名无效。 191 | pub fn sign( 192 | &mut self, 193 | private_key: &[u8], 194 | prev_TXs: HashMap, 195 | ) -> Result<()> { 196 | if self.is_coinbase() { 197 | return Ok(()); 198 | } 199 | 200 | for vin in &self.vin { 201 | if prev_TXs.get(&vin.txid).unwrap().id.is_empty() { 202 | return Err(format_err!("ERROR: Previous transaction is not correct")); 203 | } 204 | } 205 | 206 | let mut tx_copy = self.trim_copy(); 207 | 208 | for in_id in 0..tx_copy.vin.len() { 209 | let prev_Tx = prev_TXs.get(&tx_copy.vin[in_id].txid).unwrap(); 210 | tx_copy.vin[in_id].signature.clear(); 211 | tx_copy.vin[in_id].pub_key = prev_Tx.vout[tx_copy.vin[in_id].vout as usize] 212 | .pub_key_hash 213 | .clone(); 214 | tx_copy.id = tx_copy.hash()?; // 将 struct 的 hash 结果存入其 id 215 | tx_copy.vin[in_id].pub_key = Vec::new(); 216 | // 对消息用私钥签名, 后面的任何人都可以拿着 其公钥和消息进行验证. 217 | // 每个节点在接收到一个交易后,都会用发送者的公钥去验证交易的签名,以确保交易是真实有效的 218 | let signature = ed25519::signature(tx_copy.id.as_bytes(), private_key); 219 | self.vin[in_id].signature = signature.to_vec(); 220 | } 221 | 222 | Ok(()) 223 | } 224 | 225 | /// Hash returns the hash of the Transaction 226 | /// 为什么不要 id 字段: 227 | /// 当我们要计算交易的哈希值时,不应该包含原有的 id 字段,因为这个 id 字段本身就是由其他字段通过哈希计算得出的。 228 | /// 如果包含原有的 id 字段,就会引入不必要的复杂性,因为在我们重新计算哈希值(例如在签名或验证过程中)时, 229 | /// id 字段本身是未知的或者变化的。 230 | /// 所以,通过创建一个新的对象副本并清除 id 字段,我们可以确保对其他所有字段进行哈希计算,从而获得一个反映这些字段内容的哈希值。在后续的签名和验证过程中,这个哈希值会被用作交易的唯一标识。 231 | pub fn hash(&self) -> Result { 232 | let mut copy = self.clone(); 233 | copy.id = String::new(); 234 | let data = serialize(©)?; 235 | let mut hasher = Sha256::new(); 236 | hasher.input(&data[..]); // 将 `Vec` 转为 `&[u8]` 切片 237 | Ok(hasher.result_str()) 238 | } 239 | 240 | /// TrimmedCopy creates a trimmed copy of Transaction to be used in signing 241 | /// 先创建一个不包含签名(signature) 和 pub_key 的"修剪版"副本,计算它的哈希值,然后用这个哈希值生成签名 242 | fn trim_copy(&self) -> Transaction { 243 | let mut vin = Vec::new(); 244 | let mut vout = Vec::new(); 245 | 246 | for v in &self.vin { 247 | vin.push(TXInput { 248 | txid: v.txid.clone(), 249 | vout: v.vout.clone(), 250 | signature: Vec::new(), 251 | pub_key: Vec::new(), 252 | }) 253 | } 254 | 255 | for v in &self.vout { 256 | vout.push(TXOutput { 257 | value: v.value, 258 | pub_key_hash: v.pub_key_hash.clone(), 259 | }) 260 | } 261 | 262 | Transaction { 263 | id: self.id.clone(), 264 | vin, 265 | vout, 266 | } 267 | } 268 | } 269 | 270 | impl TXOutput { 271 | /// IsLockedWithKey checks if the output can be used by the owner of the pubkey 272 | /// 定义 TXOutput(交易输出)的方法 : 273 | /// 在区块链交易中,锁定交易输出实际上就是将交易输出与一个特定的公钥哈希(也就是地址)相关联。 274 | /// 这个步骤确保了只有拥有相应私钥的用户才能在将来的交易中使用这个输出 275 | 276 | //检查当前输出是否被给定的公钥哈希锁定。如果当前输出的公钥哈希与给定的公钥哈希相等,那么返回true,否则返回false。 277 | pub fn is_locked_with_key(&self, pub_key_hash: &[u8]) -> bool { 278 | self.pub_key_hash == pub_key_hash 279 | } 280 | 281 | /// Lock signs the output 282 | /// 锁定当前的输出到一个特定的地址。它将给定地址解码为公钥哈希,然后将该公钥哈希设置为当前输出的公钥哈希。 283 | fn lock(&mut self, address: &str) -> Result<()> { 284 | let pub_key_hash = Address::decode(address).unwrap().body; 285 | debug!("lock: {}", address); 286 | self.pub_key_hash = pub_key_hash; 287 | Ok(()) 288 | } 289 | 290 | /// 创建新的交易输出 - address 是 value将 要被锁定到的地址 291 | pub fn new(value: i32, address: String) -> Result { 292 | let mut txo = TXOutput { 293 | value, 294 | pub_key_hash: Vec::new(), 295 | }; 296 | txo.lock(&address)?; 297 | Ok(txo) 298 | } 299 | } 300 | 301 | 302 | #[cfg(test)] 303 | mod test { 304 | use super::*; 305 | 306 | #[test] 307 | fn test_signature() { 308 | let mut ws = Wallets::new().unwrap(); 309 | let wa1 = ws.create_wallet(); 310 | let w = ws.get_wallet(&wa1).unwrap().clone(); 311 | ws.save_all().unwrap(); 312 | drop(ws); 313 | 314 | let data = String::from("test"); 315 | let tx = Transaction::new_coinbase(wa1, data).unwrap(); 316 | assert!(tx.is_coinbase()); 317 | 318 | let signature = ed25519::signature(tx.id.as_bytes(), &w.secret_key); 319 | assert!(ed25519::verify(tx.id.as_bytes(), &w.public_key, &signature)); 320 | } 321 | } -------------------------------------------------------------------------------- /demos/blockchain-rust/src/utxoset.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | #![allow(unused)] 3 | //! unspend transaction output set 4 | 5 | use super::*; 6 | use crate::block::*; 7 | use crate::blockchain::*; 8 | use crate::transaction::*; 9 | use bincode::{deserialize, serialize}; 10 | use sled; 11 | use std::collections::HashMap; 12 | 13 | /// UTXOSet represents UTXO set 14 | /// 设计 UTXO 的意义: 使代码的语义更加明确,提高代码的模块化,并可能提供一些特定于 UTXO 集的操作和数据 15 | pub struct UTXOSet { 16 | pub blockchain: Blockchain, 17 | } 18 | 19 | impl UTXOSet { 20 | /// FindUnspentTransactions returns a list of transactions containing unspent outputs 21 | /// 在 UTXO 集合中查找可用于此交易的 TXOutputs(struct TXOutputs{outputs: Vec,}) , 22 | /// 返回的是一个 accumulated 和 unspent_outputs 的元组。 23 | /// 此方法会遍历所有存储在数据库中的未花费交易输出,找到一个满足以下条件的输出集合: 24 | /// 它们被指定的公钥(pub_key_hash) 锁定,且它们的总价值 > amount 参数。这些输出可以用于创建一个新的交易。 25 | /// 当 accumulated 总价值 > amount 时,即停止查找, 直接返回当前找到的 unspent_outputs 进行后续的花费 26 | pub fn find_spendable_outputs( 27 | &self, 28 | pub_key_hash: &[u8], 29 | amount: i32, 30 | ) -> Result<(i32, HashMap>)> { 31 | let mut unspent_outputs: HashMap> = HashMap::new(); 32 | let mut accumulated = 0; 33 | 34 | let db = sled::open("data/utxos")?; 35 | for kv in db.into_iter() { // db 是个可迭代 obj 36 | let (k, v) = kv?; 37 | let txid = String::from_utf8(k.to_vec())?; 38 | let outs: TXOutputs = deserialize(&v.to_vec())?; 39 | 40 | for out_idx in 0..outs.outputs.len() { 41 | // 当 accumulated 总价值 > amount 时,停止查找, 直接利用 unspent_outputs 进行后续的花费 42 | if outs.outputs[out_idx].is_locked_with_key(pub_key_hash) && accumulated < amount { 43 | accumulated += outs.outputs[out_idx].value; 44 | match unspent_outputs.get_mut(&txid) { 45 | Some(v) => v.push(out_idx as i32), 46 | None => { 47 | unspent_outputs.insert(txid.clone(), vec![out_idx as i32]); 48 | } 49 | } 50 | } 51 | } 52 | } 53 | 54 | Ok((accumulated, unspent_outputs)) 55 | } 56 | 57 | /// FindUTXO finds UTXO for a public key hash 58 | /// 找到所有被指定公钥哈希锁定的未花费交易输出。这些输出代表了 pub_key_hash 这个地址的 "余额" 59 | /// ( Tips: find_UTXO 和上面的代码有部分重合, 但是如果想复用 find_UTXO 函数, 60 | /// 需要对其进行一些修改,比如添加一个累计值参数,并在函数中进行价值的计算和比较。 61 | /// 但这样可能会破坏 find_UTXO 函数的原有功能,所以我个人不建议这样做。) 62 | pub fn find_UTXO(&self, pub_key_hash: &[u8]) -> Result { 63 | let mut utxos = TXOutputs { 64 | outputs: Vec::new(), 65 | }; 66 | let db = sled::open("data/utxos")?; 67 | 68 | for kv in db.iter() { 69 | let (_, v) = kv?; 70 | let outs: TXOutputs = deserialize(&v.to_vec())?; 71 | 72 | for out in outs.outputs { 73 | if out.is_locked_with_key(pub_key_hash) { 74 | utxos.outputs.push(out.clone()) 75 | } 76 | } 77 | } 78 | 79 | Ok(utxos) 80 | } 81 | 82 | /// CountTransactions returns the number of transactions in the UTXO set 83 | /// 返回数据库中存储的所有地址的所有未花费交易输出的数量 84 | pub fn count_transactions(&self) -> Result { 85 | let mut counter = 0; 86 | let db = sled::open("data/utxos")?; 87 | for kv in db.iter() { 88 | kv?; 89 | counter += 1; 90 | } 91 | Ok(counter) 92 | } 93 | 94 | /// Reindex rebuilds the UTXO set 95 | /// 重建UTXO集合。它首先删除数据库中的所有数据,然后通过查找区块链中的所有未花费交易输出来重新填充数据库。 96 | pub fn reindex(&self) -> Result<()> { 97 | std::fs::remove_dir_all("data/utxos").ok(); 98 | let db = sled::open("data/utxos")?; 99 | 100 | // 这个 find_UTXO() 是定义在 Blockchain 上的, 和上面不同 101 | let utxos = self.blockchain.find_UTXO(); 102 | 103 | for (txid, outs) in utxos { 104 | db.insert(txid.as_bytes(), serialize(&outs)?)?; 105 | } 106 | 107 | Ok(()) 108 | } 109 | 110 | /// Update updates the UTXO set with transactions from the Block 111 | /// 112 | /// The Block is considered to be the tip of a blockchain 113 | /// 此方法会用区块中的交易来更新UTXO集合。对于每个交易,它会从数据库中移除已经被花费的输出,并添加新的未花费输出。 114 | pub fn update(&self, block: &Block) -> Result<()> { 115 | let db = sled::open("data/utxos")?; 116 | 117 | for tx in block.get_transaction() { 118 | if !tx.is_coinbase() { 119 | for vin in &tx.vin { 120 | let mut update_outputs = TXOutputs { 121 | outputs: Vec::new(), 122 | }; 123 | let outs: TXOutputs = deserialize(&db.get(&vin.txid)?.unwrap().to_vec())?; 124 | for out_idx in 0..outs.outputs.len() { 125 | if out_idx != vin.vout as usize { 126 | update_outputs.outputs.push(outs.outputs[out_idx].clone()); 127 | } 128 | } 129 | 130 | if update_outputs.outputs.is_empty() { 131 | db.remove(&vin.txid)?; 132 | } else { 133 | db.insert(vin.txid.as_bytes(), serialize(&update_outputs)?)?; 134 | } 135 | } 136 | } 137 | 138 | let mut new_outputs = TXOutputs { 139 | outputs: Vec::new(), 140 | }; 141 | for out in &tx.vout { 142 | new_outputs.outputs.push(out.clone()); 143 | } 144 | 145 | db.insert(tx.id.as_bytes(), serialize(&new_outputs)?)?; 146 | } 147 | Ok(()) 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /demos/blockchain-rust/src/wallets.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | #![allow(unused)] 3 | //! bitcoin wallet 4 | 5 | use super::*; 6 | use bincode::{deserialize, serialize}; 7 | use bitcoincash_addr::*; 8 | use crypto::digest::Digest; 9 | use crypto::ed25519; 10 | use crypto::ripemd160::Ripemd160; 11 | use crypto::sha2::Sha256; 12 | use rand::{Rng, RngCore}; 13 | use serde::{Deserialize, Serialize}; 14 | use sled; 15 | use std::collections::HashMap; 16 | use log::info; 17 | use rand::rngs::OsRng; 18 | 19 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] 20 | pub struct Wallet { 21 | pub secret_key: Vec, 22 | pub public_key: Vec, 23 | } 24 | 25 | impl Wallet { 26 | /// NewWallet creates and returns a Wallet 27 | /// 首先生成一个随机的32字节的密钥,然后使用这个密钥生成一个 Ed25519的公钥/私钥对, 28 | /// 然后将这个公钥/私钥对存储在 Wallet 结构体中 29 | fn new() -> Self { 30 | let mut key: [u8; 32] = [0; 32]; 31 | let mut rand = OsRng::default(); 32 | rand.fill_bytes(&mut key); 33 | let (secret_key, public_key) = ed25519::keypair(&key); 34 | let secret_key = secret_key.to_vec(); 35 | let public_key = public_key.to_vec(); 36 | Wallet { 37 | secret_key, 38 | public_key, 39 | } 40 | } 41 | 42 | /// GetAddress returns wallet address 43 | /// 首先将公钥进行哈希计算,然后将哈希后的结果编码为一个比特币地址 44 | pub fn get_address(&self) -> String { 45 | let mut pub_hash: Vec = self.public_key.clone(); 46 | hash_pub_key(&mut pub_hash); // 先 SHA256, 再 RIPEMD160 取 20 字节 47 | let address = Address { // size = 32 48 | body: pub_hash, 49 | scheme: Scheme::Base58, // 使用 Base58 编码方案 50 | hash_type: HashType::Script, // 该地址对应的是一个脚本而非单一的公钥 51 | ..Default::default() 52 | }; // 这个结构体用于表示一个比特币地址 53 | address.encode().unwrap() // 使用 Base58Codec 对 Address 结构体进行编码,并返回这个编码后的地址字符串 54 | } // 这是比特币地址常用的一种编码方式,它可以在可读性好的同时,提供一定的错误检测功能 55 | } 56 | 57 | /// HashPubKey hashes public key 58 | /// 对公钥进行哈希计算。它首先使用SHA256算法对公钥进行哈希,然后再使用RIPEMD160算法对结果进行哈希, 59 | /// 得到的结果是一个 20 字节的哈希值 60 | pub fn hash_pub_key(pubKey: &mut Vec) { 61 | let mut hasher1 = Sha256::new(); 62 | hasher1.input(pubKey); 63 | hasher1.result(pubKey); 64 | let mut hasher2 = Ripemd160::new(); 65 | hasher2.input(pubKey); 66 | pubKey.resize(20, 0); 67 | hasher2.result(pubKey); 68 | } 69 | 70 | pub struct Wallets { 71 | wallets: HashMap, 72 | } 73 | 74 | impl Wallets { 75 | /// NewWallets creates Wallets and fills it from a file if it exists 76 | /// 从 db 中读取钱包数据,创建一个 Wallets HashMap 77 | pub fn new() -> Result { 78 | let mut wlt = Wallets { 79 | wallets: HashMap::::new(), 80 | }; 81 | let db = sled::open("data/wallets")?; 82 | 83 | for item in db.into_iter() { 84 | let i = item?; 85 | let address = String::from_utf8(i.0.to_vec())?; 86 | let wallet = deserialize(&i.1.to_vec())?; 87 | wlt.wallets.insert(address, wallet); 88 | } 89 | drop(db); //虽然 db 会在作用域结束后自动 drop, 但这里希望显式地立即释放. 90 | Ok(wlt) 91 | } 92 | 93 | /// CreateWallet adds a Wallet to Wallets 94 | pub fn create_wallet(&mut self) -> String { 95 | let wallet = Wallet::new(); 96 | let address = wallet.get_address(); 97 | self.wallets.insert(address.clone(), wallet); 98 | info!("create wallet: {}", address); 99 | address 100 | } 101 | 102 | /// GetAddresses returns an array of addresses stored in the wallet file 103 | pub fn get_all_addresses(&self) -> Vec { 104 | let mut addresses = Vec::::new(); 105 | for (address, _) in &self.wallets { 106 | addresses.push(address.clone()); 107 | } 108 | addresses 109 | } 110 | 111 | /// GetWallet returns a Wallet by its address 112 | pub fn get_wallet(&self, address: &str) -> Option<&Wallet> { 113 | self.wallets.get(address) 114 | } 115 | 116 | /// SaveToFile saves wallets to a file 117 | pub fn save_all(&self) -> Result<()> { 118 | let db = sled::open("data/wallets")?; 119 | 120 | for (address, wallet) in &self.wallets { 121 | let data = serialize(wallet)?; 122 | db.insert(address, data)?; 123 | } 124 | 125 | db.flush()?; 126 | drop(db); 127 | Ok(()) 128 | } 129 | } 130 | 131 | #[cfg(test)] 132 | mod test { 133 | use super::*; 134 | 135 | #[test] 136 | fn test_create_wallet_and_hash() { 137 | let w1 = Wallet::new(); 138 | let w2 = Wallet::new(); 139 | assert_ne!(w1, w2); 140 | assert_ne!(w1.get_address(), w2.get_address()); 141 | 142 | let mut p2 = w2.public_key.clone(); 143 | hash_pub_key(&mut p2); 144 | assert_eq!(p2.len(), 20); 145 | let pub_key_hash = Address::decode(&w2.get_address()).unwrap().body; 146 | assert_eq!(pub_key_hash, p2); 147 | } 148 | 149 | #[test] 150 | fn test_wallets() { 151 | let mut ws = Wallets::new().unwrap(); 152 | let wa1 = ws.create_wallet(); 153 | let w1 = ws.get_wallet(&wa1).unwrap().clone(); 154 | ws.save_all().unwrap(); 155 | 156 | let ws2 = Wallets::new().unwrap(); 157 | let w2 = ws2.get_wallet(&wa1).unwrap(); 158 | assert_eq!(&w1, w2); 159 | } 160 | 161 | #[test] 162 | #[should_panic] 163 | fn test_wallets_not_exist() { 164 | let w3 = Wallet::new(); 165 | let ws2 = Wallets::new().unwrap(); 166 | ws2.get_wallet(&w3.get_address()).unwrap(); 167 | } 168 | 169 | #[test] 170 | fn test_signature() { 171 | let w = Wallet::new(); 172 | let signature = ed25519::signature("test".as_bytes(), &w.secret_key); 173 | assert!(ed25519::verify( 174 | "test".as_bytes(), 175 | &w.public_key, 176 | &signature 177 | )); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /derive-macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "derive-macro" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | syn = "1.0" 10 | quote = "1.0" 11 | proc-macro2 = "1.0" 12 | 13 | 14 | [lib] 15 | proc-macro = true 16 | -------------------------------------------------------------------------------- /derive-macro/src/lib.rs: -------------------------------------------------------------------------------- 1 | // 导入所需库 2 | extern crate proc_macro; 3 | use proc_macro::TokenStream; 4 | use quote::quote; 5 | use syn::{parse_macro_input, DeriveInput}; 6 | 7 | // 使用 proc_macro_derive 属性标记自定义派生宏,并将宏命名为 simple_debug_derive。 8 | #[proc_macro_derive(SimpleDebug)] 9 | pub fn simple_debug_derive(input: TokenStream) -> TokenStream { 10 | // 将输入的 TokenStream 解析为 DeriveInput 结构体。 11 | let input_ast = parse_macro_input!(input as DeriveInput); 12 | // 从 DeriveInput 结构体中提取类型的名称。 13 | let name = &input_ast.ident; 14 | 15 | // 使用 quote 宏构造实现 SimpleDebug 的代码。 16 | let expanded = quote! { 17 | // 为指定类型实现 std::fmt::Debug trait。 18 | impl std::fmt::Debug for #name { 19 | // 实现 fmt 方法。 20 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 21 | // 使用 write! 宏将类型名称写入 Formatter。 22 | write!(f, "Instance of {}", stringify!(#name)) 23 | } 24 | } 25 | }; 26 | 27 | // 将生成的代码转换为 TokenStream 并返回。 28 | expanded.into() 29 | } 30 | -------------------------------------------------------------------------------- /function-like-macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "function-like-macro" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | syn = "1.0" 10 | quote = "1.0" 11 | proc-macro2 = "1.0" 12 | 13 | [lib] 14 | proc-macro = true -------------------------------------------------------------------------------- /function-like-macro/src/lib.rs: -------------------------------------------------------------------------------- 1 | // lib.rs 2 | extern crate proc_macro; 3 | use proc_macro::TokenStream; 4 | use quote::quote; 5 | use syn::{parse_macro_input, DeriveInput}; 6 | 7 | #[proc_macro_derive(ImplAddIntegers)] 8 | pub fn impl_add_integers(input: TokenStream) -> TokenStream { 9 | let input = parse_macro_input!(input as DeriveInput); 10 | let name = &input.ident; 11 | 12 | let expanded = quote! { 13 | impl #name { 14 | pub fn add_integers(a: i32, b: i32) -> i32 { 15 | a + b 16 | } 17 | } 18 | }; 19 | 20 | TokenStream::from(expanded) 21 | } 22 | -------------------------------------------------------------------------------- /images/Dim Invest.md: -------------------------------------------------------------------------------- 1 | 1 投资以促进一些变革性的产业,吸血传统产业,提高整个社会的生产力 2 | 3 | 2 投资并从中受益 4 | 5 | 3 投资市场、二级市场一级市场 6 | 7 | 4 风险 8 | 9 | 5 资金来源:目前只有自有资金了,怎么能弄到LP的资金以及怎么能管理好LP的资金 10 | 11 | 6 目前只布局了加密市场 12 | -------------------------------------------------------------------------------- /images/Dim Search.md: -------------------------------------------------------------------------------- 1 | # 1 追求风险 2 | 3 | 不追求稳定的工作,工作可以积累经验,但是工作经验转为财富的速度和力度都太慢 4 | 5 | 追求机遇,提升自己捕捉机遇的能力 6 | 降低消费 7 | 8 | 冒险,机会来的时候要大胆冒险 9 | 10 | 辞掉工作 11 | 12 | 节税 13 | 14 | ## 几种不同类型的资产标的 15 | 16 | 1.缓慢型 17 | 18 | 2.稳定型 19 | 20 | 3.周期型 21 | 22 | 4.快速型 23 | 24 | 5.反转型 25 | 26 | 6.隐蔽型 27 | 28 | # 2 股票大作手操盘术 29 | 30 | 不要过早卖出,一旦时机成熟,危险信号会发出,并有足够多的时间让我立场 31 | 32 | 也不要过早的买入,图上会出现漂亮的信号,并有足够的时间让我入场 33 | 34 | 未来属于那些聪明、信息流通和耐心的投机者 35 | 36 | 猥琐发育,不要显摆 37 | 38 | # 3 最近要读很多关于投资的书 39 | 40 | 技术类的 41 | 42 | 心态类的 43 | 44 | 宏观研究类的 45 | 46 | 经济周期类的 47 | 48 | # 4 创新城市 49 | 50 | (北京、上海、广州、深圳、香港、成都、重庆、武汉、南京、西安、郑州) 51 | 52 | # 5 投创领域 53 | 54 | ## DIM INVEST:投资(股市+债市+商品+现金) 55 | 56 | ## DIM CREATE:创新(科研+产品+产业+消费) 57 | 58 | ### 1 医疗健康 59 | 60 | ### 2 能源科技 61 | 62 | 能源转换与应用 63 | 64 | ### 3 人工智能 65 | 66 | ### 4 量子技术 67 | 68 | ### 5 航空航天 69 | 70 | ### 6 生物农业 71 | 72 | ### 7 材料化学 73 | 74 | ### 8 信息技术 75 | 76 | ### 9 海洋技术 77 | 78 | ### 10 生活消费 79 | 80 | ### 11 基础科学 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /images/chatdata_training_examples.md: -------------------------------------------------------------------------------- 1 | ``` 2 | When answering questions, 3 | you need to follow the data types defined in the schema and ensure that the fields used in your query statement exist in the types defined in the schema. 4 | For example, if there is a type called Wallet that has only one field named tokenBalance and no field named balance, 5 | you cannot define a field named balance when answering questions. 6 | You need to follow the types defined in the schema layer by layer and only use the fields defined in the schema to answer questions. 7 | If the question does not explicitly specify a field, you need to summarize the closest field based on the question, and then provide an answer. 8 | 9 | 10 | example 1: 11 | 12 | questions: 13 | 查一下这个合约: 0xf2A22B900dde3ba18Ec2AeF67D4c8C1a0DAB6aAC 14 | Examine this contract: 0xf2A22B900dde3ba18Ec2AeF67D4c8C1a0DAB6aAC. 15 | 16 | answer: 17 | 18 | query Query($contractAddress: String!) { 19 | ethereum { 20 | contract(contractAddress: $contractAddress) { 21 | address 22 | name 23 | symbol 24 | supportedErcInterfaces 25 | isVerified 26 | } 27 | } 28 | } 29 | 30 | 31 | variables = { 32 | "contractAddress": "0xf2A22B900dde3ba18Ec2AeF67D4c8C1a0DAB6aAC" 33 | } 34 | 35 | 36 | 37 | example 2: 38 | 39 | question: 40 | Please check what is the ENS associated with the account 0xEf1c6E67703c7BD7107eed8303Fbe6EC2554BF6B 41 | 42 | answer: 43 | 44 | query Query($address: String!) { 45 | ethereum { 46 | walletByAddress(address: $address) { 47 | ensName 48 | } 49 | } 50 | } 51 | 52 | variables = { 53 | "address": "0xEf1c6E67703c7BD7107eed8303Fbe6EC2554BF6B" 54 | } 55 | 56 | example 3: 57 | 58 | question: 59 | How many trend collections are there? 60 | 61 | 62 | answer: 63 | 64 | query Query { 65 | ethereum { 66 | trendingCollections { 67 | totalCount 68 | } 69 | } 70 | } 71 | 72 | 73 | variables = {} 74 | 75 | example 4: 76 | 77 | question: 78 | lookup details of transaction 0x2aacd75331374679e82001424fe817ee08085ca12356dd84bd49739bef8bbf9f 79 | 80 | answer: 81 | 82 | query Query($hash: String!) { 83 | ethereum { 84 | transaction(hash: $hash) { 85 | blockNumber 86 | blockTimestamp 87 | } 88 | } 89 | } 90 | 91 | variables = { 92 | 'hash':"0x2aacd75331374679e82001424fe817ee08085ca12356dd84bd49739bef8bbf9f" 93 | } 94 | 95 | a wrong example: please try to understand this point 96 | 97 | question: 98 | Please check the balance of this account address: 0x668e8A0DB87FA6ce64B2e13eD12a3981f59ef418 99 | 100 | wrong answer: 101 | 102 | query Query($address: String!) { 103 | ethereum { 104 | walletByAddress(address: $address) { 105 | balance 106 | } 107 | } 108 | } 109 | 110 | 111 | 112 | variables = { 113 | "address": "0x668e8A0DB87FA6ce64B2e13eD12a3981f59ef418" 114 | } 115 | 116 | right answer: 117 | 118 | query Query($address: String!) { 119 | ethereum { 120 | walletByAddress(address: $address) { 121 | address 122 | tokenBalances { 123 | totalCount 124 | } 125 | } 126 | } 127 | } 128 | 129 | variables = { 130 | "address": "0x668e8A0DB87FA6ce64B2e13eD12a3981f59ef418" 131 | } 132 | 133 | ``` 134 | 135 | ``` 136 | You are currently reading a GraphQL schema, which allows users to easily query on-chain data through these schemas. Assuming you are a GraphQL expert, you now need to understand various forms of questions raised by users and provide appropriate answers. The answer consists of two parts: one is a valid GraphQL query statement, and the other is the query statement's parameters. Some examples are provided below for your reference. Additionally, please note that your GraphQL query statements should strictly follow the types defined in the schema and cannot be customized. If the user's question does not correspond to any schema fields, you need to understand the user's intent and select the closest field to construct the GraphQL query statement. 137 | 138 | example 1: 139 | 140 | possible questions: 141 | 1. Query the contract with the address 0xf2A22B900dde3ba18Ec2AeF67D4c8C1a0DAB6aAC. 142 | 2. Please check the contract at 0xf2A22B900dde3ba18Ec2AeF67D4c8C1a0DAB6aAC. 143 | 3. Can you look up the contract located at 0xf2A22B900dde3ba18Ec2AeF67D4c8C1a0DAB6aAC? 144 | 4. Investigate the contract identified by 0xf2A22B900dde3ba18Ec2AeF67D4c8C1a0DAB6aAC. 145 | 5. Examine the contract associated with the address 0xf2A22B900dde3ba18Ec2AeF67D4c8C1a0DAB6aAC. 146 | 147 | your answer(Although the above questions are in different forms, they express the same meaning, so the answer to these questions is the same, therefore you need to fully understand the user's question): 148 | 149 | query Query($contractAddress: String!) { 150 | ethereum { 151 | contract(contractAddress: $contractAddress) { 152 | address 153 | name 154 | symbol 155 | supportedErcInterfaces 156 | isVerified 157 | } 158 | } 159 | } 160 | 161 | variables = { 162 | "contractAddress": "0xf2A22B900dde3ba18Ec2AeF67D4c8C1a0DAB6aAC" 163 | } 164 | 165 | 166 | example 2: 167 | 168 | possible questions: 169 | 1. Can you look up the ENS linked to the account 0xEf1c6E67703c7BD7107eed8303Fbe6EC2554BF6B? 170 | 2. Investigate the ENS connected with the account address 0xEf1c6E67703c7BD7107eed8303Fbe6EC2554BF6B. 171 | 3. Examine the ENS corresponding to the account 0xEf1c6E67703c7BD7107eed8303Fbe6EC2554BF6B. 172 | 4. Determine the ENS related to the account with the address 0xEf1c6E67703c7BD7107eed8303Fbe6EC2554BF6B. 173 | 5. Find the ENS associated with the account at 0xEf1c6E67703c7BD7107eed8303Fbe6EC2554BF6B. 174 | 175 | your answer(Although the above questions are in different forms, they express the same meaning, so the answer to these questions is the same, therefore you need to fully understand the user's question): 176 | 177 | query Query($address: String!) { 178 | ethereum { 179 | walletByAddress(address: $address) { 180 | ensName 181 | } 182 | } 183 | } 184 | 185 | variables = { 186 | "address": "0xEf1c6E67703c7BD7107eed8303Fbe6EC2554BF6B" 187 | } 188 | 189 | 190 | example 3: 191 | 192 | possible questions: 193 | 194 | 1. How many NFTs are contained in the wallet 0x2aacd75331374679e82001424fe817ee08085ca12356dd84bd49739bef8bbf9f? 195 | 2. What is the count of NFTs held in the wallet 0x2aacd75331374679e82001424fe817ee08085ca12356dd84bd49739bef8bbf9f? 196 | 3. Can you determine the number of NFTs within the wallet 0x2aacd75331374679e82001424fe817ee08085ca12356dd84bd49739bef8bbf9f? 197 | 4. What's the quantity of NFTs in the wallet with the address 0x2aacd75331374679e82001424fe817ee08085ca12356dd84bd49739bef8bbf9f? 198 | 5. How many NFTs does the wallet at 0x2aacd75331374679e82001424fe817ee08085ca12356dd84bd49739bef8bbf9f possess? 199 | 200 | your answer(Please note that this request corresponds to a deep query hierarchy with multiple levels of nesting. When constructing GraphQL query statements, you also need to first understand the user's request purpose, then read the schema content layer by layer, and decide what information to provide to the user. In general, user requests may be vague, so you only need to provide important field information and not all field information): 201 | 202 | query Query($address: String!) { 203 | ethereum { 204 | walletByAddress(address: $address) { 205 | walletNFTs { 206 | totalCount 207 | edges { 208 | node { 209 | nftsCount 210 | nft { 211 | name 212 | tokenId 213 | description 214 | contract { 215 | address 216 | name 217 | symbol 218 | } 219 | } 220 | } 221 | } 222 | } 223 | } 224 | } 225 | } 226 | 227 | variables = { 228 | 'hash':"0x2aacd75331374679e82001424fe817ee08085ca12356dd84bd49739bef8bbf9f" 229 | } 230 | 231 | 232 | 233 | example 4: a wrong example: please try to understand this point 234 | 235 | question: 236 | Please check the balance of this account address: 0x668e8A0DB87FA6ce64B2e13eD12a3981f59ef418 237 | 238 | wrong answer: 239 | 240 | query Query($address: String!) { 241 | ethereum { 242 | walletByAddress(address: $address) { 243 | balance 244 | } 245 | } 246 | } 247 | 248 | 249 | variables = { 250 | "address": "0x668e8A0DB87FA6ce64B2e13eD12a3981f59ef418" 251 | } 252 | 253 | Why is the example above incorrect? Because the 'balance' field is not defined in the schema provided to you, using this field would result in an invalid GraphQL query statement. Here is the correct answer: Note that the user wants to query the 'balance' field, but it is not defined in the schema, so we chose the closest meaning field 'tokenBalances'. Since 'tokenBalances' has several subfields, we continue to query layer by layer and return some important field information to the user. 254 | 255 | right answer: 256 | 257 | query Query($address: String!) { 258 | ethereum { 259 | walletByAddress(address: $address) { 260 | address 261 | tokenBalances { 262 | totalCount 263 | edges { 264 | node { 265 | totalBalance 266 | contractAddress 267 | contract { 268 | name 269 | symbol 270 | decimals 271 | } 272 | } 273 | } 274 | } 275 | } 276 | } 277 | } 278 | 279 | 280 | variables = { 281 | "address": "0x668e8A0DB87FA6ce64B2e13eD12a3981f59ef418" 282 | } 283 | 284 | example 5: 285 | 286 | possible questions: 287 | Please look up the transaction history for this account: 0x8d296ecc0bfed0a0d22a01fa0b23c459bce42e83 288 | 289 | your answer(The following answer is a possible result, as the user has only informed you that they need to query the account's transactions without providing further specifications. Therefore, you need to use your own judgment to provide relevant information): 290 | 291 | query Query($address: String!) { 292 | ethereum { 293 | walletByAddress(address: $address) { 294 | transactions { 295 | totalCount 296 | edges { 297 | node { 298 | fromAddress 299 | toAddress 300 | blockNumber 301 | blockTimestamp 302 | gas 303 | value 304 | } 305 | } 306 | } 307 | } 308 | } 309 | } 310 | 311 | variables = { 312 | "address": "0x8d296ecc0bfed0a0d22a01fa0b23c459bce42e83" 313 | } 314 | 315 | An example of how to understand a schema: for instance, the following schema definition has three fields under Query, and the types of these three fields are all EVMSchemaType. Under the EVMSchemaType type, there are many other fields defined, such as walletByAddress(address: String!): Wallet. This field requires an address parameter when used and returns a Wallet type, and Wallet in turn defines many types, such as tokenBalances, which returns a WalletTokenBalancesConnection type, and so on. When building a valid GraphQL query statement, you need to query each field layer by layer, meaning you can match the user's request with the meaning of the field names and select the field that is most relevant. It is important to reiterate that the GraphQL query statement fields you construct must come from the schema and cannot be customized, or else an invalid query statement will be generated.Also please note: there are too many levels involved here, and not all of them are listed. 316 | 317 | type Query { 318 | ethereum: EVMSchemaType! 319 | ethereumSepolia: EVMSchemaType! 320 | polygon: EVMSchemaType! 321 | } 322 | 323 | type EVMSchemaType { 324 | trendingCollections( 325 | filter: TrendingCollectionsFilterInput 326 | orderBy: TrendingOrderBy 327 | """The direction you want to order results: ASC/DESC. Defaults to DESC.""" 328 | orderDirection: OrderDirection 329 | before: String 330 | after: String 331 | first: Int 332 | last: Int 333 | ): EVMSchemaTypeTrendingCollectionsConnection! 334 | walletByENS(ensName: String!): Wallet 335 | walletByAddress(address: String!): Wallet 336 | contracts(filter: ContractsFilterInput, before: String, after: String, first: Int, last: Int): ContractsConnection! 337 | contract(contractAddress: String!): Contract 338 | collections(filter: CollectionsFilterInput, before: String, after: String, first: Int, last: Int): EVMSchemaTypeCollectionsConnection! 339 | collection(contractAddress: String!): Collection 340 | nft( 341 | """The address of the contract that the nft is under""" 342 | contractAddress: String! 343 | """The id of the nft""" 344 | tokenId: String! 345 | ): NFT 346 | tokenEvents(filter: TokenEventsFilterInput, before: String, after: String, first: Int, last: Int): EVMSchemaTypeTokenEventsConnection! 347 | } 348 | 349 | type Wallet { 350 | address: String! 351 | ensName: String 352 | heldCollection(collectionAddress: String!): WalletCollection @deprecated(reason: "Use wallet.collection instead.") 353 | heldCollections( 354 | orderBy: WalletCollectionOrderBy 355 | filter: WalletCollectionsFilterInput 356 | """The direction you want to order results: ASC/DESC. Defaults to DESC.""" 357 | orderDirection: OrderDirection 358 | before: String 359 | after: String 360 | first: Int 361 | last: Int 362 | ): WalletHeldCollectionsConnection! @deprecated(reason: "Use wallet.collections instead.") 363 | walletCollection(collectionAddress: String!): WalletCollection 364 | walletCollections( 365 | orderBy: WalletCollectionOrderBy 366 | filter: WalletCollectionsFilterInput 367 | """The direction you want to order results: ASC/DESC. Defaults to DESC.""" 368 | orderDirection: OrderDirection 369 | before: String 370 | after: String 371 | first: Int 372 | last: Int 373 | ): WalletWalletCollectionsConnection! 374 | tokenEvents(filter: TokenEventsFilterInput, before: String, after: String, first: Int, last: Int): WalletTokenEventsConnection! 375 | transactions(filter: TransactionsFilterInput, before: String, after: String, first: Int, last: Int): WalletTransactionsConnection! 376 | heldNft(contractAddress: String!, tokenId: String!): WalletNFT @deprecated(reason: "Use wallet.nft instead.") 377 | heldNfts( 378 | orderBy: WalletNFTsOrderBy 379 | filter: WalletNFTsFilterInput 380 | """The direction you want to order results: ASC/DESC. Defaults to DESC.""" 381 | orderDirection: OrderDirection 382 | before: String 383 | after: String 384 | first: Int 385 | last: Int 386 | ): WalletHeldNFTsConnection! @deprecated(reason: "Use wallet.nfts instead.") 387 | walletNFT(contractAddress: String!, tokenId: String!): WalletNFT 388 | walletNFTs( 389 | orderBy: WalletNFTsOrderBy 390 | filter: WalletNFTsFilterInput 391 | """The direction you want to order results: ASC/DESC. Defaults to DESC.""" 392 | orderDirection: OrderDirection 393 | before: String 394 | after: String 395 | first: Int 396 | last: Int 397 | ): WalletNFTsConnection! 398 | heldTokenBalances( 399 | orderBy: WalletTokenBalanceOrder 400 | """The direction you want to order results: ASC/DESC. Defaults to DESC.""" 401 | orderDirection: OrderDirection 402 | before: String 403 | after: String 404 | first: Int 405 | last: Int 406 | ): WalletHeldTokenBalancesConnection! @deprecated(reason: "Use wallet.tokenBalances instead.") 407 | tokenBalances( 408 | orderBy: WalletTokenBalanceOrder 409 | """The direction you want to order results: ASC/DESC. Defaults to DESC.""" 410 | orderDirection: OrderDirection 411 | before: String 412 | after: String 413 | first: Int 414 | last: Int 415 | ): WalletTokenBalancesConnection! 416 | } 417 | ``` 418 | 419 | -------------------------------------------------------------------------------- /images/invest shorts.md: -------------------------------------------------------------------------------- 1 | ![image-20230417203123417](/Users/qinjianquan/Library/Application Support/typora-user-images/image-20230417203123417.png) -------------------------------------------------------------------------------- /images/prelude_traits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/706creators/rust-co-learn/02a2a2141c7fcc577d410c161831138f3ec45bfb/images/prelude_traits.png -------------------------------------------------------------------------------- /images/smart_pointers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/706creators/rust-co-learn/02a2a2141c7fcc577d410c161831138f3ec45bfb/images/smart_pointers.png -------------------------------------------------------------------------------- /images/traits_fetures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/706creators/rust-co-learn/02a2a2141c7fcc577d410c161831138f3ec45bfb/images/traits_fetures.png -------------------------------------------------------------------------------- /module-five/.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore 2 | target/ -------------------------------------------------------------------------------- /module-five/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "module-five" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | reqwest = { version = "0.11", features = ["blocking", "json"] } 10 | tokio = { version = "1", features = ["full"] } 11 | serde = { version = "1.0", features = ["derive"] } 12 | -------------------------------------------------------------------------------- /module-five/examples/main.rs: -------------------------------------------------------------------------------- 1 | // use reqwest::{blocking::Client, Error}; 2 | // use serde::Deserialize; 3 | // use std::vec::Vec; 4 | // use tokio; 5 | 6 | // #[derive(Deserialize, Debug)] 7 | // struct Post { 8 | // userId: u32, 9 | // id: u32, 10 | // title: String, 11 | // body: String, 12 | // } 13 | 14 | // async fn fetch_post_async(url: &str) -> Result { 15 | // let response = reqwest::get(url).await?; 16 | // let response = response.error_for_status()?; 17 | // let post: Post = response.json().await?; 18 | // Ok(post) 19 | // } 20 | 21 | // fn fetch_post_sync(url: &str) -> Result { 22 | // let client = Client::new(); 23 | // let response = client.get(url).send()?; 24 | // let response = response.error_for_status()?; 25 | // let post: Post = response.json()?; 26 | // Ok(post) 27 | // } 28 | 29 | // #[tokio::main] 30 | // async fn main() -> Result<(), Box> { 31 | // let urls = vec![ 32 | // "https://jsonplaceholder.typicode.com/posts/1", 33 | // "https://jsonplaceholder.typicode.com/posts/2", 34 | // "https://jsonplaceholder.typicode.com/posts/3", 35 | // ]; 36 | 37 | // let urls_clone = urls.clone(); 38 | 39 | // println!("同步请求:"); 40 | // let sync_thread = std::thread::spawn(move || { 41 | // for url in &urls_clone { 42 | // match fetch_post_sync(url) { 43 | // Ok(post) => println!("Post信息: {:?}", post), 44 | // Err(err) => eprintln!("请求失败: {:?}", err), 45 | // } 46 | // } 47 | // }); 48 | // sync_thread.join().unwrap(); 49 | 50 | // println!("异步请求:"); 51 | // let mut tasks = Vec::new(); 52 | // for url in urls { 53 | // let task = tokio::spawn(async move { 54 | // match fetch_post_async(&url).await { 55 | // Ok(post) => println!("Post信息: {:?}", post), 56 | // Err(err) => eprintln!("请求失败: {:?}", err), 57 | // } 58 | // }); 59 | // tasks.push(task); 60 | // } 61 | 62 | // for task in tasks { 63 | // task.await?; 64 | // } 65 | 66 | // Ok(()) 67 | // } 68 | fn main() {} 69 | -------------------------------------------------------------------------------- /module-five/src/asyn_programming/async_await.rs: -------------------------------------------------------------------------------- 1 | //! 异步实战 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | use reqwest::{blocking::Client, Error}; 8 | use serde::Deserialize; 9 | use std::vec::Vec; 10 | use tokio; 11 | 12 | #[derive(Deserialize, Debug)] 13 | struct Post { 14 | userId: u32, 15 | id: u32, 16 | title: String, 17 | body: String, 18 | } 19 | 20 | async fn fetch_post_async(url: &str) -> Result { 21 | let response = reqwest::get(url).await?; 22 | let response = response.error_for_status()?; 23 | let post: Post = response.json().await?; 24 | Ok(post) 25 | } 26 | 27 | fn fetch_post_sync(url: &str) -> Result { 28 | let client = Client::new(); 29 | let response = client.get(url).send()?; 30 | let response = response.error_for_status()?; 31 | let post: Post = response.json()?; 32 | Ok(post) 33 | } 34 | 35 | #[tokio::main] 36 | async fn main() -> Result<(), Box> { 37 | let urls = vec![ 38 | "https://jsonplaceholder.typicode.com/posts/1", 39 | "https://jsonplaceholder.typicode.com/posts/2", 40 | "https://jsonplaceholder.typicode.com/posts/3", 41 | ]; 42 | 43 | let urls_clone = urls.clone(); 44 | 45 | println!("同步请求:"); 46 | 47 | let sync_start = std::time::Instant::now(); 48 | let sync_thread = std::thread::spawn(move || { 49 | for url in &urls_clone { 50 | match fetch_post_sync(url) { 51 | Ok(post) => println!("Post信息: {:?}", post), 52 | Err(err) => eprintln!("请求失败: {:?}", err), 53 | } 54 | } 55 | }); 56 | sync_thread.join().unwrap(); 57 | let sync_duration = sync_start.elapsed().as_millis(); 58 | println!("同步请求总耗时:{} ms", sync_duration); 59 | 60 | println!("异步请求:"); 61 | let async_start = std::time::Instant::now(); 62 | let mut tasks = Vec::new(); 63 | for url in urls { 64 | let task = tokio::spawn(async move { 65 | match fetch_post_async(&url).await { 66 | Ok(post) => println!("Post信息: {:?}", post), 67 | Err(err) => eprintln!("请求失败: {:?}", err), 68 | } 69 | }); 70 | tasks.push(task); 71 | } 72 | 73 | for task in tasks { 74 | task.await?; 75 | } 76 | let async_duration = async_start.elapsed().as_millis(); 77 | println!("异步请求总耗时:{} ms", async_duration); 78 | 79 | let ratio = sync_duration as f64 / async_duration as f64; 80 | println!("同步请求耗时是异步请求耗时的 {:.2} 倍", ratio); 81 | 82 | Ok(()) 83 | } 84 | 85 | ``` 86 | */ 87 | 88 | pub fn async_await() { 89 | println!(""); 90 | } 91 | 92 | // Cargo.toml中的依赖项 93 | // reqwest = { version = "0.11", features = ["blocking", "json"] } 94 | // tokio = { version = "1", features = ["full"] } 95 | // serde = { version = "1.0", features = ["derive"] } 96 | -------------------------------------------------------------------------------- /module-five/src/asyn_programming/mod.rs: -------------------------------------------------------------------------------- 1 | //! 5.2 异步编程 2 | //! 3 | 4 | pub mod async_await; 5 | -------------------------------------------------------------------------------- /module-five/src/ccur_programming/create_thread.rs: -------------------------------------------------------------------------------- 1 | //! 创建线程 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | // main函数是主线程 8 | fn main() { 9 | // 创建线程 10 | 11 | use std::thread; 12 | 13 | let mut threads = vec![]; 14 | 15 | // 创建5个线程,它们和main函数的线程是并行的,并且执行结束的时间不一定 16 | for i in 0..5 { 17 | let handle = thread::spawn(move || { 18 | println!("Hello from thread {}", i); 19 | }); 20 | 21 | threads.push(handle); 22 | } 23 | 24 | // 等待线程执行结束 25 | for thread in threads { 26 | thread.join().unwrap(); 27 | } 28 | } 29 | 30 | ``` 31 | */ 32 | 33 | pub fn create_thread() { 34 | println!(""); 35 | } 36 | -------------------------------------------------------------------------------- /module-five/src/ccur_programming/mod.rs: -------------------------------------------------------------------------------- 1 | //! 5.1 并发编程 2 | //! 3 | 4 | pub mod create_thread; 5 | pub mod share_resource; 6 | -------------------------------------------------------------------------------- /module-five/src/ccur_programming/share_resource.rs: -------------------------------------------------------------------------------- 1 | //! 资源共享 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | // main函数是主线程 9 | fn main() { 10 | // 1 通过 channel 共享数据 11 | 12 | use std::sync::mpsc; 13 | use std::thread; 14 | 15 | // 创建通道(信息接收者和信息发送者) 16 | 17 | let (tx, rx) = mpsc::channel(); 18 | 19 | thread::spawn(move || { 20 | let tx1 = tx.clone(); 21 | let tx2 = tx.clone(); 22 | 23 | // 在线程中创建变量 24 | let val1 = String::from("hi"); 25 | let val2 = String::from("hello"); 26 | 27 | // 将变量发送给别的线程 28 | tx1.send(val1).unwrap(); 29 | tx2.send(val2).unwrap(); 30 | // println!("{:?}", val); // 不能再使用 31 | }); 32 | 33 | // 接收数据 34 | for received in rx { 35 | println!("Got: {}", received); 36 | } 37 | 38 | // 2 使用锁共享数据 39 | 40 | use std::sync::{Arc, Mutex}; 41 | 42 | // 在使用线程时,我们需要将数据移入线程内,但是一旦移入,数据就不可用了,所以使用引用计数容器Arc共享所有权 43 | // 同时通过Mutex来保证独占访问 44 | 45 | let counter = Arc::new(Mutex::new(0)); 46 | let mut handles = vec![]; 47 | 48 | for _ in 0..10 { 49 | let counter = Arc::clone(&counter); 50 | 51 | let handle = thread::spawn(move || { 52 | // 拿到锁 53 | let mut num = counter.lock().unwrap(); 54 | // 修改数据 55 | *num += 1; 56 | 57 | // 锁释放 58 | // lock 调用会一个叫做 MutexGuard 的智能指针 59 | // 这个智能指针实现了 Deref 和 Drop trait 60 | // 可以自动解引用以及丢弃值 61 | // 此处自动调用了 drop() 62 | }); 63 | 64 | handles.push(handle); 65 | } 66 | 67 | // 等待所有线程完成 68 | for handle in handles { 69 | handle.join().unwrap(); 70 | } 71 | println!("Result: {}", *counter.lock().unwrap()); 72 | 73 | // 3 使用原子类型共享数据 74 | 75 | use std::sync::atomic::{compiler_fence, AtomicBool}; 76 | 77 | // 创建一个AtomicBool型的自旋锁,通过Arc包裹以在多线程之间共享 78 | let spin_lock = Arc::new(AtomicBool::new(false)); 79 | 80 | // 创建两个引用到同一个自旋锁的克隆 81 | let spin_lock_clone = Arc::clone(&spin_lock); 82 | let sc = Arc::clone(&spin_lock); 83 | 84 | let thread = thread::spawn(move || { 85 | // 用SeqCst内存顺序将锁状态设为true,表示该锁被占用。SeqCst可以确保此操作对所有线程立即可见, 86 | // 即无论其他线程在何处,他们都能看到这个改变 87 | spin_lock_clone.store(true, std::sync::atomic::Ordering::SeqCst); 88 | println!("spin_lock status a {:?}", sc); 89 | 90 | // 休眠2秒 91 | let time = std::time::Duration::from_secs(2); 92 | std::thread::sleep(time); 93 | 94 | // 设置一个编译器栅栏,内存顺序是Release。这意味着这个栅栏之前的所有操作(包括上面的println!和sleep)都会在这个栅栏之前完成。 95 | // Release语义:保证所有在此之前的操作都先执行完毕,确保在你更改共享数据之前,所有其他线程对这个数据的引用都已经完成 96 | compiler_fence(std::sync::atomic::Ordering::Release); 97 | 98 | // 使用SeqCst内存顺序将锁状态设为false,表示锁已经释放。SeqCst可以保证这个操作对所有线程立即可见 99 | spin_lock_clone.store(false, std::sync::atomic::Ordering::SeqCst); 100 | println!("spin_lock status b {:?}", sc); 101 | }); 102 | 103 | // 主线程在这里会持续检查自旋锁的状态,只要锁的值为true(被占用),就会等待。 104 | // 这里也使用SeqCst内存顺序来保证锁状态的读取能在多线程中同步 105 | while spin_lock.load(std::sync::atomic::Ordering::SeqCst) == true { 106 | println!("spin_lock status c {:?}", spin_lock) 107 | } 108 | 109 | println!("spin_lock status d {:?}", spin_lock); 110 | 111 | if let Err(e) = thread.join() { 112 | println!("Thread had an error {:?}", e); 113 | } 114 | } 115 | 116 | ``` 117 | */ 118 | 119 | pub fn share_resource() { 120 | println!(""); 121 | } 122 | -------------------------------------------------------------------------------- /module-five/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc( 2 | html_playground_url = "https://play.rust-lang.org/", 3 | test(no_crate_inject, attr(deny(warnings))), 4 | test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) 5 | )] 6 | 7 | pub mod asyn_programming; 8 | pub mod ccur_programming; 9 | -------------------------------------------------------------------------------- /module-four/.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore 2 | target/ -------------------------------------------------------------------------------- /module-four/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "module-four" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | thiserror = "1.0.40" -------------------------------------------------------------------------------- /module-four/example.txt: -------------------------------------------------------------------------------- 1 | "rust" -------------------------------------------------------------------------------- /module-four/examples/main.rs: -------------------------------------------------------------------------------- 1 | /// 1. 文档注释,一般写在当前文件的最顶端 2 | /// 3 | /// 4 | /// 5 | /// 6 | 7 | fn main() { 8 | // 1 单元测试 9 | } 10 | 11 | use std::fs::File; 12 | use std::io::Error; 13 | 14 | fn read_file(path: &str) -> Result { 15 | // 2.1 读取文件 16 | let file = File::open(path); 17 | 18 | // 2.2 判断文件是否存在 19 | match file { 20 | Ok(file) => Ok(file), 21 | Err(error) => Err(error), 22 | } 23 | } 24 | 25 | #[derive(Debug)] 26 | struct Rectangle { 27 | width: u32, 28 | height: u32, 29 | } 30 | 31 | impl Rectangle { 32 | fn can_hold(&self, other: &Rectangle) -> bool { 33 | self.width > other.width && self.height > other.height 34 | } 35 | } 36 | 37 | pub fn add_two(a: i32) -> i32 { 38 | a + 2 39 | } 40 | 41 | pub struct Guess { 42 | value: i32, 43 | } 44 | 45 | impl Guess { 46 | pub fn new(value: i32) -> Guess { 47 | if value < 1 || value > 100 { 48 | panic!("Guess value must be between 1 and 100, got {}.", value); 49 | } 50 | 51 | Guess { value } 52 | } 53 | } 54 | 55 | #[cfg(test)] 56 | mod tests { 57 | use super::*; 58 | 59 | // 1 使用 assert! 宏断言结果是抖为 true 60 | 61 | #[test] 62 | fn larger_can_hold_smaller() { 63 | let larger = Rectangle { 64 | width: 8, 65 | height: 7, 66 | }; 67 | let smaller = Rectangle { 68 | width: 5, 69 | height: 1, 70 | }; 71 | 72 | assert!(larger.can_hold(&smaller)); // 可以直接断言,也可以带上提示信息 73 | assert!( 74 | larger.can_hold(&smaller), 75 | "larger is {:?}, smaller is {:?}", 76 | larger, 77 | smaller 78 | ); 79 | } 80 | 81 | // 2 使用 assert_eq! 宏断言两个值相等 82 | 83 | #[test] 84 | fn it_adds_two() { 85 | assert_eq!(4, add_two(2)); 86 | } 87 | 88 | // 3 使用 assert_ne! 宏断言两个值不相等 89 | #[test] 90 | fn it_adds_two() { 91 | assert_ne!(3, add_two(2)); 92 | } 93 | 94 | // 4 使用 should_panic 宏断言函数会 panic 95 | 96 | #[test] 97 | #[should_panic] 98 | fn greater_than_100() { 99 | Guess::new(200); 100 | } 101 | 102 | // 5 使用Result类型的断言 103 | 104 | #[test] 105 | fn read_file_should_works() -> Result<(), String> { 106 | match read_file("rust.txt") { 107 | Ok(_) => Ok(()), 108 | Err(_) => Err(String::from("file did not exit")), 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /module-four/rust.txt: -------------------------------------------------------------------------------- 1 | "rust" -------------------------------------------------------------------------------- /module-four/src/error_handle/error_handle.rs: -------------------------------------------------------------------------------- 1 | //! 错误处理 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | // 1 类型系统保证函数契约 8 | fn sum(a: i32, b: i32) -> i32 { 9 | a + b 10 | } 11 | 12 | // sum(1u32, 2u32) 违反函数契约 13 | 14 | // 2 使用Option处理有值或无值的情况 15 | // 当某个值可能为无值时,应该使用Option来包裹,以正确处理无值的情况 16 | fn log(val: f64) -> Option { 17 | match val.log2() { 18 | x if x.is_normal() => Some(x), // 有值情况 19 | _ => None, // 无值情况 20 | } 21 | } 22 | 23 | // 当一个值为Option时,经常使用map和and_then等方法来链式处理 24 | 25 | fn double(val: f64) -> f64 { 26 | val * 2. 27 | } 28 | 29 | fn square(val: f64) -> f64 { 30 | val.powi(2 as i32) 31 | } 32 | 33 | fn inverse(val: f64) -> f64 { 34 | val * -1. 35 | } 36 | 37 | fn sqrt(val: f64) -> Option { 38 | match val.sqrt() { 39 | x if x.is_normal() => Some(x), 40 | _ => None, 41 | } 42 | } 43 | 44 | let number = 20.; 45 | let result = Option::from(number) 46 | .map(inverse) 47 | .map(double) 48 | .map(inverse) 49 | .and_then(log) 50 | .map(square) 51 | .and_then(sqrt); 52 | match result { 53 | Some(x) => println!("x was {:?}", x), 54 | None => println!("this failed"), 55 | } 56 | 57 | // 3 Result 用于处理成功或失败的情况 58 | 59 | use std::fs::File; 60 | use std::io::prelude::*; 61 | 62 | 63 | fn read_file_contents(file_path: &str) -> Result { 64 | let mut file = File::open(file_path)?; 65 | let mut contents = String::new(); 66 | file.read_to_string(&mut contents)?; 67 | Ok(contents) 68 | } 69 | 70 | let file_path = "example.txt"; 71 | match read_file_contents(file_path) { 72 | Ok(contents) => println!("File contents: {}", contents), // 成功情况 73 | Err(error) => println!("Error reading file: {}", error), // 失败情况,抛出错误 74 | } 75 | 76 | // 4 断言 77 | // 当你确定某个值一定会出现某种情况时,可以使用断言来终止程序 78 | 79 | fn extend_vec(v: &mut Vec, i: i32) { 80 | assert!(v.len() == 3); // 断言 81 | v.push(i) 82 | } 83 | 84 | let mut vec = vec![1, 2, 3]; 85 | extend_vec(&mut vec, 4); 86 | 87 | assert_eq!(4, vec[3]); // 断言 88 | 89 | // 5 恐慌 90 | // 当你确定某个值一定不会出现某种情况时,可以使用恐慌来终止程序 91 | // 92 | 93 | fn factorial(n: u32) -> u32 { 94 | if n == 0 { 95 | 1 96 | } else { 97 | n * factorial(n - 1) 98 | } 99 | } 100 | 101 | let result = factorial(10); 102 | println!("Result: {}", result); 103 | if result < 1000 { 104 | panic!("Result too large!"); // 使用panic!恐慌 105 | } 106 | 107 | // 总结:使用Option和Result来处理值或者错误,使用恐慌和断言来终止程序 108 | 109 | ``` 110 | */ 111 | 112 | pub fn error_handle() { 113 | println!(""); 114 | } 115 | -------------------------------------------------------------------------------- /module-four/src/error_handle/error_handle_example.rs: -------------------------------------------------------------------------------- 1 | //! 使用第三方库自定义错误 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | // 扩展:使用第三方库thiserror来自定义错误 8 | 9 | use std::io; 10 | use thiserror::Error; 11 | 12 | 13 | 14 | #[derive(Error, Debug)] 15 | pub enum DataStoreError { 16 | #[error("data store disconnected")] 17 | Disconnect(#[from] io::Error), 18 | #[error("the data for key `{0}` is not available")] 19 | Redaction(String), 20 | #[error("invalid header (expected {expected:?}, found {found:?})")] 21 | InvalidHeader { expected: String, found: String }, 22 | #[error("unknown data store error")] 23 | Unknown, 24 | } 25 | 26 | fn read_data(key: &str) -> Result<(), DataStoreError> { 27 | if key == "invalid_key" { 28 | return Err(DataStoreError::Redaction(format!( 29 | "The data for key `{}` is not available", 30 | key 31 | ))); 32 | } 33 | 34 | // 读取数据的逻辑... 35 | 36 | Ok(()) 37 | } 38 | 39 | match read_data("valid_key") { 40 | Ok(()) => println!("read success"), 41 | Err(err) => println!("error: {:?}", err), 42 | } 43 | 44 | 45 | ``` 46 | */ 47 | 48 | pub fn error_handle_example() { 49 | println!(""); 50 | } 51 | -------------------------------------------------------------------------------- /module-four/src/error_handle/mod.rs: -------------------------------------------------------------------------------- 1 | //! 4.1 错误处理 2 | //! 3 | 4 | pub mod error_handle; 5 | pub mod error_handle_example; 6 | -------------------------------------------------------------------------------- /module-four/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc( 2 | html_playground_url = "https://play.rust-lang.org/", 3 | test(no_crate_inject, attr(deny(warnings))), 4 | test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) 5 | )] 6 | 7 | pub mod error_handle; 8 | // pub mod project_management; 9 | pub mod project_tests; 10 | 11 | pub use my_add::*; 12 | mod my_add { 13 | 14 | pub fn add() -> i32 { 15 | 2 + 2 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /module-four/src/project_management/mod.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/706creators/rust-co-learn/02a2a2141c7fcc577d410c161831138f3ec45bfb/module-four/src/project_management/mod.rs -------------------------------------------------------------------------------- /module-four/src/project_tests/doc_test.rs: -------------------------------------------------------------------------------- 1 | //! 4.3.2 文档测试 2 | //! 3 | //! 4 | 5 | /// ``` 6 | /// fn add(a: i32, b: i32) -> i32 { 7 | /// a + b 8 | /// } 9 | /// let result = add(2, 3); 10 | /// assert_eq!(result, 5); 11 | 12 | /// ``` 13 | fn doc_test() {} 14 | -------------------------------------------------------------------------------- /module-four/src/project_tests/mod.rs: -------------------------------------------------------------------------------- 1 | //! 4.3 测试 2 | //! 3 | 4 | pub mod doc_test; 5 | pub mod unit_test; 6 | -------------------------------------------------------------------------------- /module-four/src/project_tests/unit_test.rs: -------------------------------------------------------------------------------- 1 | //! 4.3.1 单元测试 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | use std::fs::File; 9 | use std::io::Error; 10 | 11 | fn read_file(path: &str) -> Result { 12 | // 2.1 读取文件 13 | let file = File::open(path); 14 | 15 | // 2.2 判断文件是否存在 16 | match file { 17 | Ok(file) => Ok(file), 18 | Err(error) => Err(error), 19 | } 20 | } 21 | 22 | #[derive(Debug)] 23 | struct Rectangle { 24 | width: u32, 25 | height: u32, 26 | } 27 | 28 | impl Rectangle { 29 | fn can_hold(&self, other: &Rectangle) -> bool { 30 | self.width > other.width && self.height > other.height 31 | } 32 | } 33 | 34 | pub fn add_two(a: i32) -> i32 { 35 | a + 2 36 | } 37 | 38 | pub struct Guess { 39 | value: i32, 40 | } 41 | 42 | impl Guess { 43 | pub fn new(value: i32) -> Guess { 44 | if value < 1 || value > 100 { 45 | panic!("Guess value must be between 1 and 100, got {}.", value); 46 | } 47 | 48 | Guess { value } 49 | } 50 | } 51 | 52 | #[cfg(test)] 53 | mod tests { 54 | use super::*; 55 | 56 | // 1 使用 assert! 宏断言结果是抖为 true 57 | 58 | #[test] 59 | fn larger_can_hold_smaller() { 60 | let larger = Rectangle { 61 | width: 8, 62 | height: 7, 63 | }; 64 | let smaller = Rectangle { 65 | width: 5, 66 | height: 1, 67 | }; 68 | 69 | assert!(larger.can_hold(&smaller)); // 可以直接断言,也可以带上提示信息 70 | assert!( 71 | larger.can_hold(&smaller), 72 | "larger is {:?}, smaller is {:?}", 73 | larger, 74 | smaller 75 | ); 76 | } 77 | 78 | // 2 使用 assert_eq! 宏断言两个值相等 79 | 80 | #[test] 81 | fn it_adds_two() { 82 | assert_eq!(4, add_two(2)); 83 | } 84 | 85 | // 3 使用 assert_ne! 宏断言两个值不相等 86 | #[test] 87 | fn it_adds_two() { 88 | assert_ne!(3, add_two(2)); 89 | } 90 | 91 | // 4 使用 should_panic 宏断言函数会 panic 92 | 93 | #[test] 94 | #[should_panic] 95 | fn greater_than_100() { 96 | Guess::new(200); 97 | } 98 | 99 | // 5 使用Result类型的断言 100 | 101 | #[test] 102 | fn read_file_should_works() -> Result<(), String> { 103 | match read_file("rust.txt") { 104 | Ok(_) => Ok(()), 105 | Err(_) => Err(String::from("file did not exit")), 106 | } 107 | } 108 | } 109 | 110 | ``` 111 | */ 112 | pub fn unit_test() {} 113 | -------------------------------------------------------------------------------- /module-four/tests/add_test.rs: -------------------------------------------------------------------------------- 1 | use module_four::add; 2 | 3 | #[test] 4 | fn it_adds_two() { 5 | assert_eq!(4, add()); 6 | } 7 | -------------------------------------------------------------------------------- /module-one/.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore 2 | target/ -------------------------------------------------------------------------------- /module-one/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "module_one" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /module-one/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "module_one" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # [workspace] 7 | # members = ["hello_rust","hello_cargo"] 8 | 9 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 10 | 11 | [dependencies] -------------------------------------------------------------------------------- /module-one/examples/main.rs: -------------------------------------------------------------------------------- 1 | /// 1. 文档注释,一般写在当前文件的最顶端 2 | 3 | fn main() { 4 | // 1 match 5 | // match 是最长用的模式匹配,主要和枚举搭配使用,以匹配不同的枚举成员 6 | 7 | match std::fs::File::open("rust.txtr") { 8 | Ok(file) => println!("{:?}", file), 9 | Err(err) => panic!("{}", err), 10 | } 11 | 12 | // 2 if let 13 | // if let 可以让我们只关注我们想要的结果 14 | 15 | if let Ok(file) = std::fs::File::open("rust.txtr") { 16 | println!("{:?}", file); 17 | } 18 | 19 | // 3 while let 20 | // 和 if let 类似,只处理正确的结果 21 | 22 | while let Ok(file) = std::fs::File::open("rust.txt") { 23 | println!("{:?}", file); 24 | } 25 | 26 | // 4 let 27 | // let 本身也是一种模式匹配 28 | // 使用 let 匹配元组中的元素 29 | 30 | let tuple = (42, true, "rust"); 31 | 32 | let (x, y, z) = tuple; 33 | 34 | println!("{:?}", x); 35 | println!("{:?}", y); 36 | println!("{:?}", z); 37 | 38 | // 3 字符串切片 39 | // 字符串本质上一个u8序列,支持切片操作 40 | let s1 = String::from("Hello Rust"); // String本质是一个指向堆上str的指针 41 | let s2 = "Hello Rust"; //&str 很简答,就是一个 str的引用 42 | 43 | // 使用切片的操作过程:可以理解为先通过指针/引用解引用到str本身,然后通过切片操作符号拿一段出来 44 | // 但拿出来的片段仍然是str,Rust是静态语言,需要在编译期确定类型的大小,所以还需要引用切片 45 | // 整个过程等价于下面 46 | let _x = &(*s1)[0..5]; //等价于 &s1[0..5]; 47 | let _y = &(*s2)[6..10]; //等价于 &s2[6..10] 48 | 49 | let slice1 = &s1[0..5]; 50 | let slice2 = &s2[6..10]; 51 | 52 | println!("slice1: {}", slice1); // Hello 53 | println!("slice2: {}", slice2); // Rust 54 | } 55 | -------------------------------------------------------------------------------- /module-one/hello_cargo/.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore 2 | target/ -------------------------------------------------------------------------------- /module-one/hello_cargo/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "hello_cargo" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /module-one/hello_cargo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello_cargo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /module-one/hello_cargo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /module-one/hello_rust/.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore 2 | target/ -------------------------------------------------------------------------------- /module-one/hello_rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello_rust" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /module-one/hello_rust/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn add(left: usize, right: usize) -> usize { 2 | left + right 3 | } 4 | 5 | #[cfg(test)] 6 | mod tests { 7 | use super::*; 8 | 9 | #[test] 10 | fn it_works() { 11 | let result = add(2, 2); 12 | assert_eq!(result, 4); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /module-one/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/706creators/rust-co-learn/02a2a2141c7fcc577d410c161831138f3ec45bfb/module-one/main -------------------------------------------------------------------------------- /module-one/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello Rust") 3 | } 4 | -------------------------------------------------------------------------------- /module-one/rust.txtr: -------------------------------------------------------------------------------- 1 | accessible -------------------------------------------------------------------------------- /module-one/src/advance_data_types/closure.rs: -------------------------------------------------------------------------------- 1 | //! 闭包 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | // 1 闭包定义 8 | 9 | // 闭包可以捕获环境变量,并且根据其对环境变量的操作可以分为以下三类 10 | 11 | let c1 = || print!("未捕获环境变量"); 12 | 13 | let v = "rust"; 14 | let c2 = || print!("捕获环境变量但不修改 {}", v); 15 | 16 | let mut s0 = String::from("hello"); 17 | 18 | // 闭包的参数写在 || 中 19 | 20 | let mut c3 = |s: String| { 21 | s0 = s + v; 22 | println!("捕获并修改环境变量 {:?}", s0) 23 | }; 24 | 25 | // 2 闭包的调用 26 | 27 | // 闭包的调用同函数一样 28 | 29 | c1(); 30 | c2(); 31 | c3(String::from("rust")); 32 | 33 | ``` 34 | */ 35 | 36 | pub fn closure() { 37 | println!(""); 38 | } 39 | -------------------------------------------------------------------------------- /module-one/src/advance_data_types/enums.rs: -------------------------------------------------------------------------------- 1 | //! 枚举 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | // 枚举 8 | // 枚举在形式上和结构体较为相似 9 | enum Subject { 10 | Math, 11 | Chinese, 12 | English(String), 13 | } 14 | 15 | // 初始化 16 | let subject = Subject::English(String::from("English")); 17 | 18 | //标准库中两个比较重要的枚举 Option和 Result 19 | // Result 用于一些处操作可能遇到错误的场景,比如打开文件时,如果成功,返回文件,遇到错误时返回一个Error 20 | use std::fs::File; 21 | 22 | let file: Result = File::open("tmp.txt"); 23 | 24 | 25 | // Option 用于一些值可能为空的情况 26 | // 如尝试获取哈希表中某个key所对应的value,当值存在时,返回值,当不存在时返回None 27 | 28 | use std::collections::HashMap; 29 | 30 | let mut map: HashMap<&str, u32> = HashMap::new(); 31 | let v1: Option<&u32> = map.get("rust"); // None 32 | println!("{:?}", v1); 33 | 34 | map.insert("rust", 1); 35 | let v2: Option<&u32> = map.get("rust"); 36 | println!("{:?}", v2); 37 | 38 | ``` 39 | */ 40 | 41 | pub fn enums() { 42 | println!(""); 43 | } 44 | -------------------------------------------------------------------------------- /module-one/src/advance_data_types/func.rs: -------------------------------------------------------------------------------- 1 | //! 函数 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | // 1 函数定义 8 | 9 | // 1.1 没有参数和返回值的函数 10 | fn foo() { 11 | println!("foo") 12 | } 13 | 14 | // 1.2 有参数和返回值的函数 15 | 16 | fn bar(s: &str) -> String { 17 | String::from(s) 18 | } 19 | 20 | // 1.3 参数类型必须显式声明,比如引用或者可变性 21 | 22 | fn foobar(mut s: &str) -> &str { 23 | s = "rust"; 24 | s 25 | } 26 | 27 | // 2 函数调用 28 | 29 | foo(); 30 | bar("Rust"); 31 | foobar("go"); 32 | 33 | // 3 函数作为参数 34 | 35 | fn a(f: fn() -> u32) -> u32 { 36 | let value = f(); 37 | 38 | value 39 | } 40 | 41 | fn b() -> u32 { 42 | 42 43 | } 44 | 45 | // 把函数作为参传给另一个函数 46 | 47 | a(b); 48 | 49 | ``` 50 | */ 51 | 52 | pub fn func() { 53 | println!(""); 54 | } 55 | -------------------------------------------------------------------------------- /module-one/src/advance_data_types/generics.rs: -------------------------------------------------------------------------------- 1 | //! 泛型 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | // 1 泛型参数的表示 9 | // 泛型参数一般用大写字母`T`表示,多个泛型参数可以使用多个大写字母 10 | // 可以把泛型当作自定义类型,必须先声明才能使用 11 | 12 | // 2 泛型如何使用 13 | // 2.1 集合 Vec 14 | // 集合vector就是由泛型提供支持的,它允许我们使用某个具体类型时再指定 15 | let v1: Vec = Vec::new(); 16 | let v2: Vec = Vec::new(); 17 | let v3: Vec = Vec::new(); 18 | 19 | // 2.2 泛型结构体 20 | // 可以声明一个泛型结构体,然后再使用的时候在指定成员的具体类型 21 | // 注意:必须先在` <> `中声明泛型参数,然后才能使用 22 | struct Type(T); 23 | struct Point { 24 | a: A, 25 | b: B, 26 | } 27 | 28 | let t1 = Type(42); 29 | let t2 = Type("rust"); 30 | 31 | let p1 = Point { a: 42, b: 42 }; 32 | let p2 = Point { a: 42.1, b: 42.1 }; 33 | 34 | // 为泛型结构体实现方法 35 | // 注意:为泛型结构体实现方法时,impl和结构体后面的泛型声明要保持一致 36 | impl Point { 37 | fn new(a: A, b: B) -> Self { 38 | Point { a, b } 39 | } 40 | } 41 | 42 | // 2.3 泛型枚举 43 | // 同样,可以定义泛型枚举 44 | enum Area { 45 | Rectangle(A), 46 | Square(B), 47 | Circle(C), 48 | } 49 | 50 | let a1: Area = Area::Rectangle(42f64); 51 | let a2: Area = Area::Square(42u64); 52 | let a3: Area = Area::Circle("100 cm^2"); 53 | 54 | // 2.4 泛型函数 55 | // 函数参数也可以是泛型, 当然泛型也需要在 `<>` 中先声明 56 | fn generics(a: T, b: B) -> T { 57 | a 58 | } 59 | generics(32, "rust"); // 32 60 | generics("rust", 32); // "rust" 61 | 62 | 63 | ``` 64 | */ 65 | 66 | pub fn generics() { 67 | println!(""); 68 | } 69 | -------------------------------------------------------------------------------- /module-one/src/advance_data_types/mod.rs: -------------------------------------------------------------------------------- 1 | //! 3 进阶数据类型 2 | //! 3 | 4 | pub mod closure; 5 | 6 | pub mod enums; 7 | pub mod func; 8 | pub mod generics; 9 | pub mod quotation; 10 | pub mod set; 11 | pub mod string; 12 | pub mod structs; 13 | -------------------------------------------------------------------------------- /module-one/src/advance_data_types/quotation.rs: -------------------------------------------------------------------------------- 1 | //! 引用 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | // 1 不可变借用 8 | let num = 42; 9 | let immutable_s = # 10 | 11 | // 2 不可变借用 12 | let mut num = 42; 13 | let mutable_s = &mut num; 14 | 15 | // 使用场景:当类型占用空间比较大时,可以通过引用来访问或者修改数据,尤其是在传递数据的场景下 16 | 17 | let person_tuple = ("Rust", 13, true); 18 | 19 | let ptr = &person_tuple; 20 | println!("{}", ptr.0); // "Rust" 21 | 22 | let mut arr = ["Rust", "Go", "C++"]; 23 | 24 | let arr_ptr = &mut arr; 25 | 26 | arr_ptr[2] = "Java"; 27 | 28 | println!("{:?}", arr_ptr) // ["Rust", "Go", "Java"] 29 | 30 | 31 | ``` 32 | */ 33 | 34 | pub fn quotation() { 35 | println!(""); 36 | } 37 | -------------------------------------------------------------------------------- /module-one/src/advance_data_types/set.rs: -------------------------------------------------------------------------------- 1 | //! 集合 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | // 1 Vec 9 | // Vec是动态大小,相比起数组来说,它更加常用 10 | // Vec中的元素必须相同 11 | let mut vec1 = Vec::new(); 12 | let mut vec2 = vec![]; 13 | 14 | // vec 支持一系列的操作 15 | 16 | // 添加元素 17 | vec1.push("Rust"); 18 | vec2.push("Go"); 19 | 20 | // 当作栈 21 | vec1.pop(); 22 | 23 | // 修改数据 24 | vec2[0] = "Rust"; 25 | 26 | // Vec 和 String一样,数据存放在堆上 27 | 28 | println!("{}", vec2.len()); // 1 29 | println!("{}", vec2.capacity()); // 4 30 | println!("{:?}", vec2.as_ptr()); // 0x7fafc9f05b70 31 | 32 | // 2 HashMap 33 | // HashMap并不是预导入的,需要手动引入当前作用域 34 | use std::collections::HashMap; 35 | 36 | // 使用new方法创建 37 | let mut scores = HashMap::new(); 38 | 39 | // 插入数据 40 | scores.insert(String::from("Blue"), 10); 41 | scores.insert(String::from("Yellow"), 50); 42 | 43 | // 修改数据,修改和插入数据是同一个api 44 | scores.insert(String::from("Blue"), 100); 45 | 46 | // 访问数据,注意访问的key传递的是引用 47 | let key = String::from("Blue"); 48 | println!("{:?}", scores[&key]) 49 | 50 | 51 | ``` 52 | */ 53 | 54 | pub fn set() { 55 | println!(""); 56 | } 57 | -------------------------------------------------------------------------------- /module-one/src/advance_data_types/string.rs: -------------------------------------------------------------------------------- 1 | //! 字符串 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | // 1 &str 8 | // 字符串字面量实际上存放在程序的只读数据段中,在程序运行时会被加载到内存中读取 9 | let s = "Hello Rust"; 10 | let mut s1 = "Hello Go"; 11 | 12 | s1 = "Hello Rust"; 13 | println!("{}", s1); 14 | 15 | // 2 String 16 | // String 是动态分配大小的,其大小在代码编译时是未知的,内部的容量是可以随时根据需要变化 17 | // 我们可以通过多种方式创建一个String 18 | // let s2 = String::new(); // 空字符串 19 | // let s2 = "Hello Rust".to_string(); 20 | // let s2: String = "Hello Rust".into(); 21 | let s2 = String::from("Hello Rust"); 22 | 23 | // String 由三部分组成:指向某些字节的指针、长度和容量。指针指向 String 于存储其数据的内部缓冲区。 24 | // 长度是缓冲区中当前存储的字节数,容量是缓冲区的大小(以字节为单位)。因此,长度将始终小于或等于容量。 25 | // 可以通过 as_ptr、len、capacity 方法访问这三个量。 26 | let ptr = s2.as_ptr(); // 返回String的指针 27 | let len = s2.len(); // 返回String的长度 28 | let cap = s2.capacity(); // 返回String的容量 29 | 30 | println!("pointer {:?}", ptr); 31 | println!("len {}", len); 32 | println!("cap {}", cap); 33 | 34 | // 3 字符串切片 35 | // 字符串本质上一个u8序列,支持切片操作 36 | let s1 = String::from("Hello Rust"); // String本质是一个指向堆上str的指针 37 | let s2 = "Hello Rust"; //&str 很简答,就是一个 str的引用 38 | 39 | // 使用切片的操作过程:可以理解为先通过指针/引用解引用到str本身,然后通过切片操作符号拿一段出来 40 | // 但拿出来的片段仍然是str,Rust是静态语言,需要在编译期确定类型的大小,所以还需要再加引用 41 | // 整个过程等价于下面, 42 | let x = &(*s1)[0..5]; //等价于 &x[0..5]; 43 | let y = &(*s2)[6..10]; //等价于 &s2[6..10] 44 | 45 | let slice1 = &x[0..5]; 46 | let slice2 = &s2[6..10]; 47 | 48 | println!("slice1: {}", slice1); // Hello 49 | println!("slice2: {}", slice2); // Rust 50 | 51 | ``` 52 | */ 53 | 54 | pub fn string() { 55 | println!(""); 56 | } 57 | -------------------------------------------------------------------------------- /module-one/src/advance_data_types/structs.rs: -------------------------------------------------------------------------------- 1 | //! 结构体 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | // 1 结构体 8 | // Rust中的结构体有三种 9 | 10 | // 1.1 常规结构体 11 | struct Language { 12 | name: String, 13 | birth: u32, 14 | is_popular: bool, 15 | } 16 | // 1.2 元组结构体 17 | struct Rust(String); 18 | 19 | // 1.3 单元结构体 20 | struct Go; 21 | 22 | // 结构体赋值 23 | let l = Language { 24 | name: String::from("rust"), 25 | birth: 2010, 26 | is_popular: true, 27 | }; 28 | 29 | // 访问结构体成员 30 | println!("{:?}", l.name); 31 | 32 | // 为结构体实现方法 33 | impl Rust { 34 | // Self 代表结构体本身 35 | fn new() -> Self { 36 | Rust(String::from("Rust")) 37 | } 38 | 39 | fn print() { 40 | let rust = Rust::new(); 41 | println!("{:?}", rust.0) 42 | } 43 | } 44 | 45 | // 调用结构体实现的宏方法 46 | let r = Rust::new(); 47 | Rust::print(); 48 | 49 | ``` 50 | */ 51 | 52 | pub fn structs() { 53 | println!(""); 54 | } 55 | -------------------------------------------------------------------------------- /module-one/src/basic_data_types/compound.rs: -------------------------------------------------------------------------------- 1 | //! 复合类型 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | // 1 元组 9 | // Rust中的元组可以将各种类型组合起来 10 | let types = (42, "Rust", true); 11 | 12 | // 可以像访问数组元素一样通过下标索引访问 13 | println!("num is {}", types.0); 14 | 15 | // 单元类型 () 16 | // 单元类型在Rust中是非常重要的类型,如果表达式不返回任何其他值,就隐式地返回单元值, 17 | // 如没有返回值的函数或者作用域 18 | let a: () = {}; 19 | fn return_tuple() {} 20 | let func: () = return_tuple(); 21 | assert_eq!(a, func); 22 | 23 | // 2 数组 24 | // 通过索引来访问或者修改数组中的元素 25 | let arr = [1, 2, 3, 4, 5]; 26 | 27 | let mut arr1 = [0, 0, 0, 0, 0]; 28 | arr1[0] = 100; 29 | println!("{:?}", arr1); // [100, 0, 0, 0, 0] 30 | 31 | ``` 32 | */ 33 | 34 | pub fn compound() { 35 | println!(""); 36 | } 37 | -------------------------------------------------------------------------------- /module-one/src/basic_data_types/mod.rs: -------------------------------------------------------------------------------- 1 | //! 2 基础数据类型 2 | 3 | pub mod compound; 4 | pub mod scalar; 5 | -------------------------------------------------------------------------------- /module-one/src/basic_data_types/scalar.rs: -------------------------------------------------------------------------------- 1 | //! 标量类型 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | // 1 整数类型 8 | // Rust 中整数类型分为有符号和无符号类型;长度分为8位,16位,32位,64位,128位 9 | // 特殊的整数类型: usize 和 isize,与系统架构相关,32位的系统则为32位,64位的系统为64位 10 | let integer: i32 = 42; 11 | let s: usize = 100; 12 | 13 | // 2 浮点类型 14 | // Rust 的浮点型是 f32 和 f64,大小分别为 32 位和 64 位。默认浮点类型是 f64 15 | // 浮点型都是有符号的 16 | let x = 2.0; // f64 17 | let y: f32 = 3.0; // f32 18 | 19 | // 3 布尔类型 20 | let t = true; 21 | let f: bool = false; 22 | 23 | // 4 字符类型 char 24 | // Rust 的字符类型大小为 4 个字节,表示的是一个 Unicode 标量值 25 | let c = 'z'; 26 | let z = 'ℤ'; 27 | let heart_eyed_cat = '😻'; 28 | 29 | ``` 30 | */ 31 | 32 | pub fn scalar() { 33 | println!(""); 34 | } 35 | -------------------------------------------------------------------------------- /module-one/src/comment/comment.rs: -------------------------------------------------------------------------------- 1 | //! 文档注释、单行、多行注释 2 | //! 3 | 4 | /// 这个函数用于计算两个整数的和。 5 | /// 6 | /// # Examples 7 | /// 8 | /// ``` 9 | /// assert_eq!(add(2, 3), 5); 10 | /// ``` 11 | fn add(x: i32, y: i32) -> i32 { 12 | x + y 13 | } 14 | 15 | /** 16 | 17 | ``` 18 | 19 | /// 1. 文档注释,一般写在当前文件的最顶端 20 | 21 | fn main() { 22 | /* 23 | 2. 多行注释 24 | Point 结构体代表二维坐标系下的一个点,通过坐标可以求的任意一点到原点的距离 25 | */ 26 | struct Point(u32, u32); 27 | 28 | // 3. 单行注释 29 | // 求某一点到原点距离的平方 30 | 31 | fn distance_square(p: Point) -> u32 { 32 | p.0 * p.0 + p.1 * p.1 33 | } 34 | 35 | let p = Point(3, 4); 36 | distance_square(p); 37 | } 38 | 39 | 40 | ``` 41 | */ 42 | 43 | pub fn comments() { 44 | println!(""); 45 | } 46 | -------------------------------------------------------------------------------- /module-one/src/comment/mod.rs: -------------------------------------------------------------------------------- 1 | //! 5 注释 2 | //! 3 | 4 | pub mod comment; 5 | -------------------------------------------------------------------------------- /module-one/src/control/circle.rs: -------------------------------------------------------------------------------- 1 | //! 循环 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | // 1 使用for循环遍历集合 9 | // 注意:Rust中的for循环本质上是迭代器的语法糖 10 | // 迭代器涉及到更复杂的知识点,后续会介绍 11 | 12 | let v = vec![1, 2, 3, 4, 5]; 13 | 14 | for num in v { 15 | println!("{}", num); 16 | } 17 | 18 | let mut map = std::collections::HashMap::new(); 19 | map.insert("a", 2); 20 | map.insert("b", 2); 21 | map.insert("c", 2); 22 | 23 | for kv_pair in map { 24 | println!("{:?}", kv_pair); 25 | } 26 | 27 | // 2 使用 loop 执行无限循环,并使用break终止 28 | 29 | let mut x = 0; 30 | 31 | loop { 32 | println!("{:?}", x); 33 | 34 | if x == 10 { 35 | break; 36 | } else { 37 | x = x + 1; 38 | } 39 | } 40 | 41 | // 3 使用 while 执行条件循环 42 | 43 | let mut x = 0; 44 | while x < 5 { 45 | println!("x is {}", x); 46 | x += 1; 47 | } 48 | 49 | 50 | ``` 51 | */ 52 | 53 | pub fn circle() { 54 | println!(""); 55 | } 56 | -------------------------------------------------------------------------------- /module-one/src/control/mod.rs: -------------------------------------------------------------------------------- 1 | //! 4 控制流程 2 | //! 3 | 4 | pub mod circle; 5 | pub mod model_match; 6 | -------------------------------------------------------------------------------- /module-one/src/control/model_match.rs: -------------------------------------------------------------------------------- 1 | //! 模式匹配 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | // 1 match 8 | // match 是最长用的模式匹配,主要和枚举搭配使用,以匹配不同的枚举成员 9 | 10 | match std::fs::File::open("rust.txtr") { 11 | Ok(file) => println!("{:?}", file), 12 | Err(err) => panic!("{}", err), 13 | } 14 | 15 | // 2 if let 16 | // if let 可以让我们只关注我们想要的结果 17 | 18 | if let Ok(file) = std::fs::File::open("rust.txtr") { 19 | println!("{:?}", file); 20 | } 21 | 22 | // 3 while let 23 | // 和 if let 类似,只处理正确的结果 24 | 25 | while let Ok(file) = std::fs::File::open("rust.txt") { 26 | println!("{:?}", file); 27 | } 28 | 29 | // 4 let 30 | // let 本身也是一种模式匹配 31 | // 使用 let 匹配元组中的元素 32 | 33 | let tuple = (42, true, "rust"); 34 | 35 | let (x, y, z) = tuple; 36 | 37 | println!("{:?}", x); 38 | println!("{:?}", y); 39 | println!("{:?}", z); 40 | 41 | ``` 42 | */ 43 | 44 | pub fn model_match() { 45 | println!(""); 46 | } 47 | -------------------------------------------------------------------------------- /module-one/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc( 2 | html_playground_url = "https://play.rust-lang.org/", 3 | test(no_crate_inject, attr(deny(warnings))), 4 | test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) 5 | )] 6 | 7 | pub mod advance_data_types; 8 | pub mod basic_data_types; 9 | pub mod comment; 10 | pub mod control; 11 | pub mod variable_mutability; 12 | -------------------------------------------------------------------------------- /module-one/src/variable_mutability/mod.rs: -------------------------------------------------------------------------------- 1 | //! 1 变量和可变性 2 | //! 3 | 4 | pub mod variable_mutability; 5 | -------------------------------------------------------------------------------- /module-one/src/variable_mutability/variable_mutability.rs: -------------------------------------------------------------------------------- 1 | //! 常量和变量 2 | //! 3 | /** 4 | 5 | ``` 6 | // 1 常量 7 | // 使用 const 声明; 常量名称使用大写字母; 显式标注类型 8 | const RUST: &str = "rust"; 9 | const WEIGHT: u64 = 100; 10 | 11 | println!("{},{}",RUST,WEIGHT); 12 | 13 | // 2 变量 14 | // 使用let 声明,大多数情况下,编译器可以根据上下文推断变量类型 15 | let name = "rust"; 16 | let age: u32 = 13; 17 | 18 | println!("{},{}",name,age); 19 | 20 | // 3 不变性 21 | // Rust中变量默认不可变,若需修改变量,需要使用mut关键字声明变量具有可变性 22 | let _language = "go"; 23 | // _language = "rust"; 无法修改 24 | 25 | // 4 可变性 26 | // 通过 mut 声明变量 27 | let mut language = "go"; 28 | language = "rust"; 29 | 30 | println!("{}", language); 31 | 32 | ``` 33 | */ 34 | 35 | pub fn variable_mutability() { 36 | println!(""); 37 | } 38 | -------------------------------------------------------------------------------- /module-six/.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore 2 | target/ -------------------------------------------------------------------------------- /module-six/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "module-six" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | lazy_static = "1.4.0" 10 | derive-macro = { path = "../derive-macro" } 11 | attribute-macro = { path = "../attribute-macro" } 12 | function-like-macro = { path = "../function-like-macro" } 13 | -------------------------------------------------------------------------------- /module-six/examples/main.rs: -------------------------------------------------------------------------------- 1 | // 导入 HashMap,用于存储键值对。 2 | use std::collections::HashMap; 3 | // 导入 lazy_static 宏,用于创建静态变量。 4 | use lazy_static::lazy_static; 5 | 6 | // 定义一个名为 `create_map` 的宏,它接受一系列键值对,并在展开时创建一个包含这些键值对的 HashMap。 7 | // 宏使用了匹配表达式 (`$key:expr => $value:expr`) 来捕获键值对,并使用重复模式 (`$()*`) 来插入每个键值对到 HashMap。 8 | macro_rules! create_map { 9 | // 接受一系列键值对,每个键值对以 `$key:expr => $value:expr` 的形式给出。 10 | // 最后一个键值对后面可以有一个可选的逗号。 11 | // $() 是指一个重复模式,用于匹配和迭代一组重复的模式 12 | // `,` 用于分隔不同的模式项 13 | // `*` 表示0次或者多次匹配 14 | // `?` 表示可选的 15 | // `{{...}}` 表示创建一个代码块 16 | ( $($key:expr => $value:expr),* $(,)? ) => {{ 17 | // 创建一个新的 HashMap。 18 | let mut map = HashMap::new(); 19 | // 使用重复模式,对每一个键值对执行以下代码。 20 | $( 21 | // 将每个键值对插入到 HashMap 中。 22 | map.insert($key, $value); 23 | )* 24 | // 返回填充好的 HashMap。 25 | map 26 | }}; 27 | } 28 | 29 | fn main() { 30 | // 使用 lazy_static 宏创建一个名为 `FRUITS` 的静态 HashMap。 31 | // 这里我们使用 `create_map!` 宏来初始化 HashMap。 32 | lazy_static! { 33 | static ref FRUITS: HashMap<&'static str, u32> = create_map! { 34 | "apple" => 1, 35 | "banana" => 2, 36 | "orange" => 3, 37 | "peach" => 4, 38 | }; 39 | } 40 | 41 | // 打印 FRUITS 的内容。注意,我们需要使用 *FRUITS 来解引用 FRUITS。 42 | println!("{:?}", *FRUITS); 43 | } 44 | -------------------------------------------------------------------------------- /module-six/src/declarative_macros/declarative_macros.rs: -------------------------------------------------------------------------------- 1 | //! 声明宏 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | // 导入 HashMap,用于存储键值对。 9 | use std::collections::HashMap; 10 | // 导入 lazy_static 宏,用于创建静态变量。 11 | use lazy_static::lazy_static; 12 | 13 | // 定义一个名为 `create_map` 的宏,它接受一系列键值对,并在展开时创建一个包含这些键值对的 HashMap。 14 | // 宏使用了匹配表达式 (`$key:expr => $value:expr`) 来捕获键值对,并使用重复模式 (`$()*`) 来插入每个键值对到 HashMap。 15 | macro_rules! create_map { 16 | // 接受一系列键值对,每个键值对以 `$key:expr => $value:expr` 的形式给出。 17 | // 最后一个键值对后面可以有一个可选的逗号。 18 | ( $($key:expr => $value:expr),* $(,)? ) => {{ 19 | // 创建一个新的 HashMap。 20 | let mut map = HashMap::new(); 21 | // 使用重复模式,对每一个键值对执行以下代码。 22 | $( 23 | // 将每个键值对插入到 HashMap 中。 24 | map.insert($key, $value); 25 | )* 26 | // 返回填充好的 HashMap。 27 | map 28 | }}; 29 | } 30 | 31 | fn main() { 32 | // 使用 lazy_static 宏创建一个名为 `FRUITS` 的静态 HashMap。 33 | // 这里我们使用 `create_map!` 宏来初始化 HashMap。 34 | lazy_static! { 35 | static ref FRUITS: HashMap<&'static str, u32> = create_map! { 36 | "apple" => 1, 37 | "banana" => 2, 38 | "orange" => 3, 39 | "peach" => 4, 40 | }; 41 | } 42 | 43 | // 打印 FRUITS 的内容。注意,我们需要使用 *FRUITS 来解引用 FRUITS。 44 | println!("{:?}", *FRUITS); 45 | } 46 | 47 | ``` 48 | */ 49 | 50 | pub fn declarative_macros() { 51 | println!(""); 52 | } 53 | 54 | // Cargo.toml中的依赖项 55 | // [dependencies] 56 | // lazy_static = "1.4.0" 57 | -------------------------------------------------------------------------------- /module-six/src/declarative_macros/mod.rs: -------------------------------------------------------------------------------- 1 | //! 声明宏 2 | //! 3 | 4 | pub mod declarative_macros; 5 | -------------------------------------------------------------------------------- /module-six/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc( 2 | html_playground_url = "https://play.rust-lang.org/", 3 | test(no_crate_inject, attr(deny(warnings))), 4 | test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) 5 | )] 6 | 7 | pub mod declarative_macros; 8 | pub mod procedural_macros; 9 | pub mod unsafe_rust; 10 | -------------------------------------------------------------------------------- /module-six/src/procedural_macros/attribute_macros.rs: -------------------------------------------------------------------------------- 1 | //! 属性宏 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | use attribute_macro::show_function_name; 8 | 9 | // 通过 #[show_function_name] 语法应用属性宏 10 | #[show_function_name] 11 | fn my_function() {} 12 | 13 | fn main() { 14 | // 调用已修改的函数 15 | my_function(); 16 | } 17 | 18 | ``` 19 | */ 20 | 21 | pub fn attribute_macro() { 22 | println!(""); 23 | } 24 | -------------------------------------------------------------------------------- /module-six/src/procedural_macros/derive_macro.rs: -------------------------------------------------------------------------------- 1 | //! 派生宏 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | use derive_macro::SimpleDebug; 8 | 9 | // 通过 #[derive(SimpleDebug)] 语法应用自定义派生宏 10 | #[derive(SimpleDebug)] 11 | struct TestStruct; 12 | 13 | fn main() { 14 | let test_instance = TestStruct; 15 | // 调用 Debug trait 的实现 16 | println!("{:?}", test_instance); 17 | } 18 | 19 | ``` 20 | */ 21 | 22 | pub fn derive_macro() {} 23 | -------------------------------------------------------------------------------- /module-six/src/procedural_macros/function_like_macros.rs: -------------------------------------------------------------------------------- 1 | //! 类函数宏 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | use function_like_macro::ImplAddIntegers; 9 | 10 | #[derive(ImplAddIntegers)] 11 | struct MyStruct; 12 | 13 | fn main() { 14 | let result = MyStruct::add_integers(3, 5); 15 | println!("The sum is: {}", result); // The sum is: 8 16 | } 17 | 18 | 19 | ``` 20 | */ 21 | 22 | pub fn function_like_macro() { 23 | println!(""); 24 | } 25 | -------------------------------------------------------------------------------- /module-six/src/procedural_macros/mod.rs: -------------------------------------------------------------------------------- 1 | //! 过程宏 2 | //! 3 | 4 | pub mod attribute_macros; 5 | pub mod derive_macro; 6 | pub mod function_like_macros; 7 | -------------------------------------------------------------------------------- /module-six/src/unsafe_rust/access_or_modify_static_var.rs: -------------------------------------------------------------------------------- 1 | //! 访问或者修改不可变的静态变量 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | static mut COUNTER: i32 = 0; 9 | 10 | fn increment_counter() { 11 | unsafe { 12 | COUNTER += 1; 13 | } 14 | } 15 | 16 | fn main() { 17 | increment_counter(); 18 | unsafe { 19 | println!("Counter value: {}", COUNTER); // 输出 "Counter value: 1" 20 | } 21 | } 22 | 23 | ``` 24 | */ 25 | 26 | pub fn access_or_modify_static_var() { 27 | println!(""); 28 | } 29 | -------------------------------------------------------------------------------- /module-six/src/unsafe_rust/call_unsafe_method.rs: -------------------------------------------------------------------------------- 1 | //! 调用不安全的函数或方法 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | unsafe fn unsafe_function() { 9 | // 执行不安全的操作,如直接操作内存或调用底层系统 API 10 | } 11 | 12 | fn main() { 13 | unsafe { 14 | unsafe_function(); // 调用不安全函数 15 | } 16 | } 17 | 18 | ``` 19 | */ 20 | 21 | pub fn call_unsafe_method() { 22 | println!(""); 23 | } 24 | -------------------------------------------------------------------------------- /module-six/src/unsafe_rust/deref_raw_pointers.rs: -------------------------------------------------------------------------------- 1 | //! 解引用裸指针 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | fn main() { 9 | let x = 10; 10 | let y = &x as *const i32; 11 | let z = 0x12345678 as *const i32; // 假设这是一个无效的内存地址 12 | 13 | unsafe { 14 | println!("Value of x: {}", *y); // 输出 "Value of x: 10" 15 | // println!("Value at address 0x12345678: {}", *z); // 不安全!可能导致未定义行为 16 | } 17 | } 18 | 19 | ``` 20 | */ 21 | 22 | pub fn dereferencing_raw_pointers() { 23 | println!(""); 24 | } 25 | -------------------------------------------------------------------------------- /module-six/src/unsafe_rust/impl_unsafe_trait.rs: -------------------------------------------------------------------------------- 1 | //! 实现不安全的trait 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | unsafe trait UnsafeTrait { 9 | unsafe fn unsafe_method(&self); 10 | } 11 | 12 | struct MyStruct { 13 | value: i32, 14 | } 15 | 16 | unsafe impl UnsafeTrait for MyStruct { 17 | unsafe fn unsafe_method(&self) { 18 | let mut raw_ptr = self as *const Self as *mut Self; 19 | (*raw_ptr).value = 42; 20 | } 21 | } 22 | 23 | fn main() { 24 | let my_struct = MyStruct { value: 10 }; 25 | 26 | unsafe { 27 | my_struct.unsafe_method(); 28 | } 29 | } 30 | 31 | ``` 32 | */ 33 | 34 | pub fn impl_unsafe_trait() { 35 | println!(""); 36 | } 37 | -------------------------------------------------------------------------------- /module-six/src/unsafe_rust/mod.rs: -------------------------------------------------------------------------------- 1 | //! Unsafe Rust 2 | //! 3 | 4 | pub mod access_or_modify_static_var; 5 | pub mod call_unsafe_method; 6 | pub mod deref_raw_pointers; 7 | pub mod impl_unsafe_trait; 8 | -------------------------------------------------------------------------------- /module-three/.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore 2 | target/ -------------------------------------------------------------------------------- /module-three/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "module-three" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /module-three/examples/main.rs: -------------------------------------------------------------------------------- 1 | /// 1. 文档注释,一般写在当前文件的最顶端 2 | /// 3 | /// 4 | 5 | fn main() { 6 | // 在展开Rust的智能指针之前,我们先区分一下Rust中的智能指针、引用和裸指针 7 | 8 | // 1 指针、引用和智能指针 9 | 10 | // 1.1 引用 11 | 12 | let x = 100; 13 | let mut y: i64 = 200; 14 | #[derive(Debug)] 15 | struct A(i32); 16 | let a = A(100); 17 | 18 | // 使用 & 获取不变或者可变引用 19 | let x_pointer = &x; 20 | let y_pointer = &mut y; 21 | let a_pointer = &a; 22 | 23 | println!("{:?}", x_pointer); // 100 打印时会自动“解引用”到数据,而不是地址 24 | println!("{:p}", x_pointer); // 0x7ff7b9bae33c 如果要打印地址的话,改变占位符?为 p 25 | 26 | // let z = &mut y; // 可变借用不能超过1次 27 | 28 | y = *y_pointer + 100; // 解引用后修改 29 | 30 | println!("{:?}", y); //300 本条代码结束后,可变借用才释放 31 | println!("{:?}", a_pointer); // A(100) 32 | 33 | // 1.2 裸指针 34 | let x = 100; 35 | let mut y: i64 = 200; 36 | struct B(i32); 37 | let a = B(100); 38 | 39 | // 裸指针是使用 as *const 从引用转换而来 40 | let x_raw_pointer = &x as *const i32; 41 | let y_raw_pointer = &mut y as *const i64; 42 | let a_raw_pointer = &a as *const B; 43 | 44 | println!("{:?}", x_raw_pointer); // 0x7ff7b763a46c,裸指针打印时不会被“解引用”到数据,而是会直接会打印地址 45 | 46 | unsafe { 47 | y = *y_raw_pointer + 300; // 裸指针解引用需要使用unsafe 语法块,这里的解引用的安全的 48 | 49 | let z_raw_pointer = &mut y as *const i64; // 第二次生成可变裸指针,unsafe 块绕过了可变借用的次数规则,是不是感觉有点危险? 50 | 51 | y = *z_raw_pointer + 500; // 然后继续改变数据 52 | 53 | println!("{:?}", *y_raw_pointer); // 1000 54 | } 55 | println!("{:?}", a_raw_pointer); // 0x7ff7b763a47c 56 | println!("{:?}", y); // 1000 57 | 58 | // 1.3 智能指针 59 | 60 | // Vec 和 String 类型都是智能指针 61 | 62 | let vec = vec![1, 2, 3, 4]; 63 | let s = "rust".to_string(); 64 | let num = Box::new(100); 65 | 66 | let v1 = vec; // 发生了move语义,现在数据的所有者不再是vec 而是v1,数据没变,拥有者变了 67 | 68 | // println!("{:?}", vec); // 不能再使用 vec,因为它不再拥有数据了 69 | 70 | let v = [1, 2, 3, 4]; 71 | let v = &v1; // 只是借用,v 仍然拥有数据 72 | println!("{:?}", v); // 所以可以使用 v 73 | 74 | // 2 智能指针与结构体、trait 75 | // Rust中的智能指针都是以结构体进行封装,然后为它实现了某些trait 76 | // 事实上,Rust中很多特殊的类型都是基于结构体来实现的,并且在这些结构体上实现了各种trait,这是一种通用的类型构造思路 77 | 78 | // 标准库中的一些智能指针的定义 79 | /* 80 | pub struct Box(_, _) 81 | where 82 | A: Allocator, 83 | T: ?Sized; 84 | 85 | pub struct String { 86 | vec: Vec, 87 | } 88 | 89 | pub struct Vec { 90 | buf: RawVec, 91 | len: usize, 92 | } 93 | 94 | pub struct Rc { 95 | ptr: NonNull>, 96 | phantom: PhantomData>, 97 | } 98 | */ 99 | 100 | // 那什么是智能指针?智能指针是实现了Deref trait 或 Drop trait 的结构体类型 101 | // Deref允许自动解引用,Drop允许自动释放资源 102 | 103 | // 2. 自定义智能指针 104 | 105 | // 2.1 实现 Drop trait 106 | 107 | #[derive(Debug)] 108 | struct User { 109 | name: String, 110 | age: u32, 111 | } 112 | 113 | impl Drop for User { 114 | fn drop(&mut self) { 115 | println!("User has been dropped {:?}:", "rust") // 实现细节只是做了打印 116 | } 117 | } 118 | 119 | // 2.2 实现 Deref trait 120 | use std::ops::Deref; 121 | 122 | #[derive(Debug)] 123 | struct MyBox(T); 124 | 125 | impl Deref for MyBox { 126 | type Target = T; 127 | fn deref(&self) -> &T { 128 | &self.0 129 | } 130 | } 131 | 132 | // 2.3 Drop trait 如何起作用的? 133 | // 当一个值离开作用域时,它的drop方法会被自动被编译器调用,无需手动调用,强行手动调用编译器会报错 134 | 135 | { 136 | let mut user = User { 137 | name: "rust".to_string(), 138 | age: 12, 139 | }; 140 | 141 | // user.drop(); //手动调用不行 因为编译器会自动调用,显式调用二者会冲突 142 | 143 | // 你会在终端发现打印了 “Rust”,成功验证,编译器确实调用了 drop 144 | } 145 | 146 | // 2.4 Deref trait 如何起作用的? 147 | 148 | { 149 | let m = MyBox("rust"); 150 | let ref_my_box = *m; // 实现了 Deref trait的智能指针可以使用 * 直接解引用到内部的值, 151 | // 等价于下面:deref函数会自动调用 152 | let ref_my_box = *(m.deref()); 153 | 154 | // String是智能指针,它实现了Deref trait,所以可以直接解引用 155 | 156 | fn take_ref_string(s: &str) { 157 | println!("{:?}", s) 158 | } 159 | 160 | // 将String解引用为str 161 | // 注意:String这个智能指针包裹的类型是 str,解引用后大小编译器无法确定,所以要再加&(引用) 162 | let s = String::from("Rust"); 163 | // take_ref_string(s); 164 | take_ref_string(&s); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /module-three/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc( 2 | html_playground_url = "https://play.rust-lang.org/", 3 | test(no_crate_inject, attr(deny(warnings))), 4 | test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) 5 | )] 6 | 7 | pub mod trait_advance; 8 | pub mod type_advance; 9 | -------------------------------------------------------------------------------- /module-three/src/trait_advance/mod.rs: -------------------------------------------------------------------------------- 1 | //! 1 trait 进阶 2 | //! 3 | 4 | pub mod trait_closure; 5 | pub mod trait_iterator; 6 | pub mod trait_smart_pointer; 7 | -------------------------------------------------------------------------------- /module-three/src/trait_advance/trait_closure.rs: -------------------------------------------------------------------------------- 1 | //! 1.1 trait与闭包 2 | //! 3 | //! 4 | 5 | /** 6 | 7 | ``` 8 | // 1. 回顾三种类型的闭包 9 | // 前面我们介绍过,闭包有三种类型:未捕获环境变量,捕获环境变量不修改,捕获环境变量并修改 10 | 11 | // 1.1 未捕获环境变量 12 | let c1 = || println!("didn't catch env var"); 13 | c1(); 14 | 15 | // 1.2 捕获但不修改环境变量 16 | let x = 10; 17 | 18 | let c2 = || println!("catch env var but not modify, x = {}", x); 19 | 20 | c2(); 21 | 22 | // 1.3 捕获并修改环境变量 23 | 24 | let mut x = 10; 25 | let mut c3 = |a: i32| { 26 | x = 1 + a; 27 | println!("catch env var and modify, x = {}", x); 28 | }; 29 | c3(10); 30 | 31 | // 2. 闭包实现与trait 32 | 33 | // 在Rust中,闭包实际上是一个语法糖,它的实现在抽象概念上可以看做是一个匿名结构体,这个结构体会把环境变量捕获成为其成员,并实现Fn/FnMut/FnOnce trait 34 | // Fn/FnMut/FnOnce中各有一个方法分别是call/call_mut/call_once,对应的语义分别是调用不可变闭包、调用可变闭包、调用消费闭包 35 | // 并且Fn/FnMut/FnOnce trait是以次继承的,也就是说实现 Fn trait,必须实现 FnMut trait,实现 FnMut trait,必须实现 FnOnce trait 36 | 37 | // 当声明一个闭包时,编译器会根据闭包的类型,自动推导出其实现的trait,一般情况下不需要手动实现 38 | 39 | // 3. 闭包作为函数参数传递 40 | // 值得注意的是,在将闭包作为参数在函数中传递时,类型的指定是通过trait来实现的 41 | 42 | fn call_fn(f: F) { 43 | f(); 44 | } 45 | 46 | fn call_fn_mut(mut f: F) { 47 | f(); 48 | } 49 | 50 | fn call_fn_once(f: F) { 51 | f(); 52 | } 53 | 54 | // 闭包的调用 case 1 55 | // Rust编译器会根据你如何调用推导出闭包的类型,也就是实现哪个trait 56 | 57 | let c = || println!("closure"); 58 | 59 | call_fn_once(c); // 实现了FnOnce trait 60 | call_fn(c); // 实现了Fn trait,FnMut trait,FnOnce trait,后面两种trait都是通过继承实现的 61 | call_fn_mut(c); // 实现了FnMut trait,FnOnce trait 62 | 63 | // 闭包的调用 case 2 64 | 65 | let x = "10"; 66 | 67 | let c = || println!("get env var {}", x); 68 | 69 | call_fn_once(c); // 实现了FnOnce trait 70 | call_fn(c); // 实现了Fn trait,FnMut trait,FnOnce trait,后面两种trait都是通过继承实现的 71 | call_fn_mut(c); // 实现了FnMut trait,FnOnce trait 72 | 73 | // 闭包的调用 case 3 74 | 75 | let mut x = String::from("10"); 76 | 77 | let mut c = || println!("get env var {x:?}", x = String::from("20")); 78 | 79 | call_fn_once(c); // 实现了FnOnce trait 80 | call_fn(c); // 实现了Fn trait,FnMut trait,FnOnce trait,后面两种trait都是通过继承实现的 81 | call_fn_mut(c); // 实现了FnMut trait,FnOnce trait 82 | 83 | // 4. 闭包作为函数返回 84 | 85 | fn return_fn() -> impl Fn() { 86 | || println!("call_fn") 87 | } 88 | 89 | fn return_i32(i: i32) -> i32 { 90 | 32 91 | } 92 | 93 | fn return_fn_mut() -> impl FnMut() { 94 | let x = 10; 95 | // || println!("call_fn_mut {}", x + 1) // 不能返回局部变量 96 | move || println!("call_fn_mut {}", x + 1) // 必须把局部变量移入闭包,才能返回(这里实际上发生了数据的复制) 97 | } 98 | 99 | fn return_fn_once() -> impl FnOnce() { 100 | let s = String::from("hello"); 101 | // || println!("call_fn_once {:?}", s) 102 | move || println!("call_fn_once {:?}", s) // 必须把局部变量移入闭包,才能返回(这里实际上发生了所有权转移) 103 | } 104 | ``` 105 | */ 106 | 107 | pub fn trait_closure() { 108 | println!(""); 109 | } 110 | -------------------------------------------------------------------------------- /module-three/src/trait_advance/trait_iterator.rs: -------------------------------------------------------------------------------- 1 | //! 1.2 trait与迭代器 2 | //! 3 | //! 4 | 5 | /** 6 | 7 | ``` 8 | // 1. for 循环与迭代器 9 | 10 | // 在rust中,for循环实际上的迭代器的语法糖 11 | 12 | // for 循环以及解糖 13 | let values = vec![1, 2, 3, 4, 5]; 14 | // 使用 for 循环遍历集合中个每个元素 15 | for x in values { 16 | println!("{x}"); 17 | } 18 | // for 循环解糖后等价如下: 19 | let v = vec![1, 2, 3, 4, 5]; 20 | // 先将集合转为迭代器类型 21 | let mut v_iter = v.into_iter(); 22 | // 在 loop 循环中使用next方法循环获取集合中下一个元素,当集合中取不到值时使用break终止 loop循环 23 | loop { 24 | match v_iter.next() { 25 | Some(x) => println!("{}", x), 26 | None => break, 27 | } 28 | } 29 | 30 | // 2. 迭代器 trait IntoIterator 和 Iterator 31 | // IntoIterator trait 中的 into_iter方法会返回一个 实现了 Iterator trait 迭代器 32 | // Iterator trait 通过其 next方法来获取集合中的下一个元素 33 | 34 | use std::collections::HashMap; 35 | use std::slice::Iter; 36 | use std::slice::IterMut; 37 | use std::vec::IntoIter; 38 | 39 | 40 | // 如果类型实现了迭代器 trait,则可以使用迭代器中的方法,例如: 41 | 42 | let map = HashMap::from([("rust", 1), ("go", 2), ("python", 3)]); 43 | let map_iter = map.into_iter(); 44 | let vec: Vec<(&str, i32)> = map_iter.collect(); 45 | println!("{:?}", vec); // [("rust", 1), ("go", 2), ("python", 3)] 46 | 47 | // 3. 迭代器、借用和所有权 48 | let mut v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; 49 | let iter_mut: IterMut = v.iter_mut(); // 转为 IterMut 结构体, 可变借用 50 | let iter: Iter = v.iter(); // 转为 Iter 结构体, 不可变借用 51 | let iter_into: IntoIter = v.into_iter(); // 转为 IntoIter 结构体 , 获取所有权 52 | 53 | // 4. 迭代器适配器 54 | let vec = vec![1, 2, 3, 4, 5]; 55 | let doubled: Vec = vec 56 | .iter() 57 | .map(|&x| x * 3) 58 | .take(3) 59 | .filter(|x| *x > 6) 60 | .collect(); 61 | println!("{:?}", doubled); // [9] 62 | 63 | // 5 迭代器与迭代器适配器特性:lazy(惰性) 64 | let v = vec![1, 2, 3, 4, 5]; 65 | v.iter().for_each(|x| println!("{x}")); 66 | // or 67 | for x in &v { 68 | println!("{x}"); 69 | } 70 | 71 | ``` 72 | */ 73 | 74 | pub fn trait_iterator() { 75 | println!(""); 76 | } 77 | -------------------------------------------------------------------------------- /module-three/src/trait_advance/trait_smart_pointer.rs: -------------------------------------------------------------------------------- 1 | //! 1.3 trait与智能指针 2 | //! 3 | //! 4 | 5 | /** 6 | 7 | ``` 8 | // 在展开Rust的智能指针之前,我们先区分一下Rust中的智能指针、引用和裸指针 9 | 10 | // 1 指针、引用和智能指针 11 | 12 | // 1.1 引用 13 | 14 | let x = 100; 15 | let mut y: i64 = 200; 16 | #[derive(Debug)] 17 | struct A(i32); 18 | let a = A(100); 19 | 20 | // 使用 & 获取不变或者可变引用 21 | let x_pointer = &x; 22 | let y_pointer = &mut y; 23 | let a_pointer = &a; 24 | 25 | println!("{:?}", x_pointer); // 100 打印时会自动“解引用”到数据,而不是地址 26 | println!("{:p}", x_pointer); // 0x7ff7b9bae33c 如果要打印地址的话,改变占位符?为 p 27 | 28 | // let z = &mut y; // 可变借用不能超过1次 29 | 30 | y = *y_pointer + 100; // 解引用后修改 31 | 32 | println!("{:?}", y); //300 本条代码结束后,可变借用才释放 33 | println!("{:?}", a_pointer); // A(100) 34 | 35 | // 1.2 裸指针 36 | let x = 100; 37 | let mut y: i64 = 200; 38 | struct B(i32); 39 | let a = B(100); 40 | 41 | // 裸指针是使用 as *const 从引用转换而来 42 | let x_raw_pointer = &x as *const i32; 43 | let y_raw_pointer = &mut y as *const i64; 44 | let a_raw_pointer = &a as *const B; 45 | 46 | println!("{:?}", x_raw_pointer); // 0x7ff7b763a46c,裸指针打印时不会被“解引用”到数据,而是会直接会打印地址 47 | 48 | unsafe { 49 | y = *y_raw_pointer + 300; // 裸指针解引用需要使用unsafe 语法块,这里的解引用的安全的 50 | 51 | let z_raw_pointer = &mut y as *const i64; // 第二次生成可变裸指针,unsafe 块绕过了可变借用的次数规则,是不是感觉有点危险? 52 | 53 | y = *z_raw_pointer + 500; // 然后继续改变数据 54 | 55 | println!("{:?}", *y_raw_pointer); // 1000 56 | } 57 | println!("{:?}", a_raw_pointer); // 0x7ff7b763a47c 58 | println!("{:?}", y); // 1000 59 | 60 | // 1.3 智能指针 61 | 62 | // Vec 和 String 类型都是智能指针 63 | 64 | let vec = vec![1, 2, 3, 4]; 65 | let s = "rust".to_string(); 66 | let num = Box::new(100); 67 | 68 | let v1 = vec; // 发生了move语义,现在数据的所有者不再是vec 而是v1,数据没变,拥有者变了 69 | 70 | // println!("{:?}", vec); // 不能再使用 vec,因为它不再拥有数据了 71 | 72 | let v = [1, 2, 3, 4]; 73 | let v = &v1; // 只是借用,v 仍然拥有数据 74 | println!("{:?}", v); // 所以可以使用 v 75 | 76 | // 2 智能指针与结构体、trait 77 | // Rust中的智能指针都是以结构体进行封装,然后为它实现了某些trait 78 | // 事实上,Rust中很多特殊的类型都是基于结构体来实现的,并且在这些结构体上实现了各种trait,这是一种通用的类型构造思路 79 | 80 | // 标准库中的一些智能指针的定义 81 | /* 82 | pub struct Box(_, _) 83 | where 84 | A: Allocator, 85 | T: ?Sized; 86 | 87 | pub struct String { 88 | vec: Vec, 89 | } 90 | 91 | pub struct Vec { 92 | buf: RawVec, 93 | len: usize, 94 | } 95 | 96 | pub struct Rc { 97 | ptr: NonNull>, 98 | phantom: PhantomData>, 99 | } 100 | */ 101 | 102 | // 那什么是智能指针?智能指针是实现了Deref trait 或 Drop trait 的结构体类型 103 | // Deref允许自动解引用,Drop允许自动释放资源 104 | 105 | // 2. 自定义智能指针 106 | 107 | // 2.1 实现 Drop trait 108 | 109 | #[derive(Debug)] 110 | struct User { 111 | name: String, 112 | age: u32, 113 | } 114 | 115 | impl Drop for User { 116 | fn drop(&mut self) { 117 | println!("User has been dropped {:?}:", "rust") // 实现细节只是做了打印 118 | } 119 | } 120 | 121 | // 2.2 实现 Deref trait 122 | use std::ops::Deref; 123 | 124 | #[derive(Debug)] 125 | struct MyBox(T); 126 | 127 | impl Deref for MyBox { 128 | type Target = T; 129 | fn deref(&self) -> &T { 130 | &self.0 131 | } 132 | } 133 | 134 | // 2.3 Drop trait 如何起作用的? 135 | // 当一个值离开作用域时,它的drop方法会被自动被编译器调用,无需手动调用,强行手动调用编译器会报错 136 | 137 | { 138 | let mut user = User { 139 | name: "rust".to_string(), 140 | age: 12, 141 | }; 142 | 143 | // user.drop(); //手动调用不行 因为编译器会自动调用,显式调用二者会冲突 144 | 145 | // 你会在终端发现打印了 “Rust”,成功验证,编译器确实调用了 drop 146 | } 147 | 148 | // 2.4 Deref trait 如何起作用的? 149 | 150 | { 151 | let m = MyBox("rust"); 152 | let ref_my_box = *m; // 实现了 Deref trait的智能指针可以使用 * 直接解引用到内部的值 153 | // 等价于下面:deref函数会自动调用 154 | let ref_my_box = *(m.deref()); 155 | 156 | // String是智能指针,它实现了Deref trait,所以可以直接解引用 157 | 158 | fn take_ref_string(s: &str) { 159 | println!("{:?}", s) 160 | } 161 | 162 | // 将String解引用为str 163 | // 注意:String这个智能指针包裹的类型是 str,解引用后大小编译器无法确定,所以要再加&(引用) 164 | let s = String::from("Rust"); 165 | // take_ref_string(s); 166 | take_ref_string(&s); 167 | } 168 | 169 | ``` 170 | */ 171 | 172 | pub fn trait_smart_pointer() { 173 | println!(""); 174 | } 175 | -------------------------------------------------------------------------------- /module-three/src/type_advance/boxs.rs: -------------------------------------------------------------------------------- 1 | //! 2.1 `Box` 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | // 1 Box 与数据分配 8 | 9 | // 在Rust中,你可以使用Box将数据强行存储到堆上 10 | 11 | let a = Box::new("rust"); 12 | let b = Box::new(42); 13 | 14 | // 它也是唯一可以将数据放到堆上的途径 15 | 16 | // 2 Box 是一个智能指针 17 | // 它实现了Deref和Drop trait 18 | 19 | let s = Box::new("rust"); 20 | let s = *s; // 解引用 21 | 22 | // 离开作用域时,会自动调用drop方法,释放堆上的数据 23 | 24 | // 这个类型比较简单,再次需要强调的是它是众多的Rust基于结构体构和trait造的特殊类型之一 25 | 26 | // 3 为什么要把数据存放在堆上?一个链表例子 27 | 28 | // 定义链表节点数据结构 29 | enum ListNode { 30 | Cons(T, Box>), 31 | Nil, 32 | } 33 | // 声明三个节点 34 | let node3 = ListNode::Cons(3, Box::new(ListNode::Nil)); 35 | let node2 = ListNode::Cons(2, Box::new(node3)); 36 | let list = ListNode::Cons(1, Box::new(node2)); 37 | 38 | // let list: ListNode = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil)))))); 39 | 40 | // 使用模式匹配解构节点值 41 | match list { 42 | ListNode::Cons(head, tail) => { 43 | println!("head: {}", head); 44 | match *tail { 45 | ListNode::Cons(head, _) => println!("second item: {}", head), 46 | ListNode::Nil => println!("there is no second item"), 47 | } 48 | } 49 | ListNode::Nil => println!("list is empty"), 50 | } 51 | 52 | ``` 53 | */ 54 | 55 | pub fn boxs() { 56 | println!(""); 57 | } 58 | -------------------------------------------------------------------------------- /module-three/src/type_advance/mod.rs: -------------------------------------------------------------------------------- 1 | //! 2 类型进阶 2 | //! 3 | 4 | pub mod boxs; 5 | pub mod mut_container; 6 | pub mod phantomdata; 7 | pub mod pin; 8 | -------------------------------------------------------------------------------- /module-three/src/type_advance/mut_container.rs: -------------------------------------------------------------------------------- 1 | //! 2.2 可变容器 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | // 1.编译期:通过 mut 显式声明变量的可变性,也叫外部可变性 9 | use std::cell::Cell; 10 | let can_not_change = "rust"; 11 | let mut can_change = "go"; 12 | // can_not_change = "cpp"; // 不可重新赋值 13 | can_change = "c"; // 可以更改 14 | 15 | // 2 一个需要改变不可变变量的例子 16 | 17 | // let var1 = 0; 18 | // let mut var2 = 0; 19 | 20 | // while var2 <= 10 { 21 | // if var2 == 10 { 22 | // var1 = 10; 23 | // } 24 | // var2 += 1; 25 | // } 26 | 27 | // println!("var1: {}, var2: {}", var1, var2); 28 | 29 | // 3. 运行期:通过Cell和RefCell实现可变性,也叫内部可变性 30 | // 3.1 Cell 的修改和读取 31 | struct Foo { 32 | x: u32, 33 | y: Cell, 34 | z: Cell>, 35 | } 36 | 37 | let foo = Foo { 38 | x: 1, 39 | y: Cell::new(3), 40 | z: Cell::new(Vec::new()), 41 | }; 42 | 43 | // 修改容器内的变量使用set方法 44 | foo.y.set(100); 45 | foo.z.set(vec!["rust".to_owned()]); 46 | 47 | // 读取容器内的变量有两种:固定大小类型可以使用 get和into_inner; 动态大小类型只能使用into_inner 48 | assert_eq!(100, foo.y.get()); 49 | assert_eq!(100, foo.y.into_inner()); 50 | 51 | // assert_eq!(vec!["rust".to_owned()], foo.z.get()); 不能使用get方法 52 | assert_eq!(vec!["rust".to_owned()], foo.z.into_inner()); 53 | 54 | // 3.2 RefCell 的修改和读取 55 | // 通过borrow_mut实现可变性 56 | // 主要是应用于一些动态大小类型,通过borrow获取值,有运行时开销 57 | 58 | use std::cell::RefCell; 59 | let vec = vec![1, 2, 3, 4]; 60 | 61 | let ref_vec = RefCell::new(vec); 62 | 63 | println!("{:?}", ref_vec.borrow()); // 不可变借用 使用borrow 64 | ref_vec.borrow_mut().push(5); // 可变借用改变,使用borrow_mut 65 | println!("{:?}", ref_vec.borrow()); 66 | 67 | ``` 68 | */ 69 | 70 | pub fn mut_container() { 71 | println!(""); 72 | } 73 | -------------------------------------------------------------------------------- /module-three/src/type_advance/phantomdata.rs: -------------------------------------------------------------------------------- 1 | //! 2.3 特殊类型 PhantomData 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | use std::marker::PhantomData; 8 | use std::ops::Deref; 9 | 10 | struct MyType { 11 | data: *const T, 12 | _marker: PhantomData, 13 | } 14 | 15 | impl MyType { 16 | fn new(t: T) -> MyType { 17 | MyType { 18 | data: &t, 19 | _marker: PhantomData, 20 | } 21 | } 22 | } 23 | 24 | impl Deref for MyType { 25 | type Target = T; 26 | 27 | fn deref(&self) -> &Self::Target { 28 | unsafe { &*self.data } 29 | } 30 | } 31 | 32 | impl Drop for MyType { 33 | fn drop(&mut self) { 34 | println!("Dropping MyType instance!"); 35 | } 36 | } 37 | 38 | let resource: MyType = MyType::new(true); 39 | let another_resource: MyType = MyType::new(32); 40 | 41 | print!("{:?}", unsafe { *(resource.data) }); 42 | print!(" {:?}", unsafe { *(another_resource.data) }); 43 | 44 | let my_instance: MyType = MyType::new(33); 45 | // 执行到这里时,my_instance 将会离开作用域并被销毁,调用我们自定义的 drop 方法。 46 | ``` 47 | */ 48 | 49 | pub fn phantomdata() { 50 | println!(""); 51 | } 52 | -------------------------------------------------------------------------------- /module-three/src/type_advance/pin.rs: -------------------------------------------------------------------------------- 1 | //! 2.4 特殊类型 Pin、PhantomPinned 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | use std::marker::PhantomPinned; 8 | use std::pin::Pin; 9 | 10 | // 定义一个自引用的结构体。因为它含有指向自身的指针,所以它在内存中不能被移动。 11 | struct SelfReferential { 12 | i: i32, 13 | p: *const i32, // 裸指针,将会指向上述的 i 14 | _pin: PhantomPinned, // 也是一个零大小的标记类型,阻止 Rust 自动为我们的类型实现 Unpin trait 15 | } 16 | 17 | // 注意此时 p 是一个空指针,我们还没有为它分配指向的地址 18 | let mut test = SelfReferential { 19 | i: 123, 20 | p: std::ptr::null(), 21 | _pin: PhantomPinned, 22 | }; 23 | 24 | // 使用 Pin 包装我们的结构体实例。这样就能保证 test 的内存地址不会在其生命周期中改变。 25 | // 注意:这里使用了 unsafe,因为我们需要保证在 test 被包装为 Pin 后,其地址不会被改变 26 | let mut test = unsafe { Pin::new_unchecked(&mut test) }; 27 | 28 | // 创建一个裸指针,指向 test 的 i 字段。注意我们使用了 test 的引用版本以保证安全。 29 | let self_ptr: *const i32 = &test.as_ref().get_ref().i; 30 | 31 | // 将裸指针存储到 test 的 p 字段。注意我们使用了 unsafe,因为我们正在直接修改内存。 32 | 33 | unsafe { 34 | let mut_ref = Pin::as_mut(&mut test); 35 | mut_ref.get_unchecked_mut().p = self_ptr; 36 | } 37 | 38 | // 打印 test 的 p 字段所指向的内容。注意我们使用了 unsafe,因为我们正在解引用裸指针。 39 | let val = unsafe { *(test.as_ref().get_ref().p) }; 40 | println!("val: {}", val); // 输出 "val: 123" 41 | ``` 42 | */ 43 | 44 | pub fn pin() { 45 | println!(""); 46 | } 47 | -------------------------------------------------------------------------------- /module-two/.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore 2 | target/ -------------------------------------------------------------------------------- /module-two/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "module-two" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /module-two/examples/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/706creators/rust-co-learn/02a2a2141c7fcc577d410c161831138f3ec45bfb/module-two/examples/main -------------------------------------------------------------------------------- /module-two/examples/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // 1. &str 3 | let mut a = "rust"; 4 | let size_of_a = std::mem::size_of_val(a); 5 | let ptr_of_a = a.as_ptr(); 6 | 7 | println!("Size of 'rust': {} bytes", size_of_a); // 打印结果:Size of 'rust': 4 bytes 8 | println!("Address of 'rust': {:p}", ptr_of_a); // 打印结果:Address of 'rust': 0x107e52fa0 9 | 10 | a = "go"; 11 | let size_of_a = std::mem::size_of_val(a); 12 | let ptr_of_a = a.as_ptr(); 13 | 14 | println!("Size of 'go': {} bytes", size_of_a); // 打印结果:Size of 'go': 2 bytes 15 | println!("Address of 'go': {:p}", ptr_of_a); // 打印结果:Address of 'go': 0x107e52fdb 16 | 17 | let ptr_of_rust = "rust".as_ptr(); // 访问初始的“rust” 18 | println!("Address of 'rust' after reassignment: {:p}", ptr_of_rust); // 打印结果:Address of 'rust' after reassignment: 0x107e52fa0 19 | 20 | let a = "rust"; 21 | 22 | let b = a; 23 | 24 | print!("--a{:p}", a.as_ptr()); 25 | print!("--b{:p}", b.as_ptr()); 26 | 27 | use std::mem; 28 | 29 | let mut s = String::with_capacity(10); 30 | let ptr_before = s.as_ptr(); 31 | println!("Capacity: {}, Address: {:?}", s.capacity(), ptr_before); 32 | 33 | s.push_str("Hello"); 34 | let ptr_during = s.as_ptr(); 35 | println!("Capacity: {}, Address: {:?}", s.capacity(), ptr_during); 36 | 37 | s.push_str(" Worldoooooooooooooooooooooooooooooooooooooooooooooooooooooooooo!"); 38 | let ptr_after = s.as_ptr(); 39 | println!("Capacity: {}, Address: {:?}", s.capacity(), ptr_after); 40 | 41 | // 确保在检查扩容后的地址时,字符串s还没有被drop,否则会出现悬垂指针 42 | mem::forget(s); 43 | } 44 | -------------------------------------------------------------------------------- /module-two/src/borrow_lifetime/borrow_rules.rs: -------------------------------------------------------------------------------- 1 | //! 2.1 借用与引用以及借用检查规则 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | let mut s = String::from("Rust"); // 对于s来说,它将值借用给了s_p 9 | let mut i = 32; 10 | 11 | let s_p = &mut s; // 对于s_p来说,它引用了s的值 12 | // let s_p1 = &mut s; // 对于s_p1来说,它引用了s的值 13 | // let s_p3 = &s; 14 | 15 | let i_p2 = &i; 16 | let i_p = &i; 17 | 18 | // s = String::from("Go"); 19 | *s_p = String::from("Java"); 20 | 21 | { 22 | let c = 'a'; 23 | 24 | let c_p = &c; 25 | println!("{}", c_p); 26 | // c_p 离开作用域,对应的值(引用)资源会被释放 27 | } 28 | 29 | // println!("{}", c_p); 30 | 31 | 32 | ``` 33 | */ 34 | 35 | pub fn borrow_lifetime() { 36 | println!(""); 37 | } 38 | -------------------------------------------------------------------------------- /module-two/src/borrow_lifetime/lifetime.rs: -------------------------------------------------------------------------------- 1 | //! 2.2 变量生命周期 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | //1 变量的生命周期 : 从声明开始,到离开作用域结束 9 | 10 | { 11 | let x = 32; // x 的生命周期开始 12 | println!("{}", x); 13 | 14 | { 15 | let x_ptr = &x; // x_ptr 的生命周期开始 16 | 17 | } // x_ptr 生命周期结束,值会被丢弃 18 | 19 | // println!("{}", x_ptr); // 无法再使用 x_ptr,因为它已经被丢弃 20 | 21 | 22 | } // x 生命周期结束,值会被丢弃 23 | 24 | ``` 25 | */ 26 | 27 | pub fn lifetime() { 28 | println!(""); 29 | } 30 | -------------------------------------------------------------------------------- /module-two/src/borrow_lifetime/lifetime_params.rs: -------------------------------------------------------------------------------- 1 | //! 2.3 生命周期参数 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | // 可以推断引用的有效性 9 | // fn return_strings(x: &String) -> &String { 10 | // let s = String::from("Rust"); 11 | 12 | // &s 13 | // } 14 | 15 | let s_p = return_string(&String::from("Rust")); 16 | 17 | fn return_string(x: &String) -> &String { 18 | x 19 | } 20 | 21 | struct Foo { 22 | x: i32, 23 | y: (i32, bool), 24 | z: String, 25 | } 26 | 27 | let f1 = Foo { 28 | x: 32, 29 | y: (32, true), 30 | z: String::from("rust"), 31 | }; 32 | 33 | let f2 = Foo { 34 | x: 32, 35 | y: (32, true), 36 | z: String::from("rust"), 37 | }; 38 | 39 | // 仍然无法编译通过,因为编译器无法推断出参数和返回值的生命周期 40 | // 这是因为Rust对于函数的检查只会检查签名,而不是函数里面的具体逻辑 41 | // 对于这个函数返回的引用,因为只从函数签名来看,返回的这个引用不知道是来自于哪里,一个可能是来自于两个参数的某一个,另一种情况是可能来自于某个内部定义的变量,这就会导致悬垂指针 42 | 43 | // 无法推断引用的有效性 44 | // fn bar(x: &Foo, y: &Foo) -> &Foo { 45 | // x 46 | // } 47 | 48 | // 通过生命周期参数显示指定参数的生命周期 49 | 50 | // &i32 // 引用 51 | // &'a i32 // 带有显式生命周期的引用 52 | // &'a mut i32 // 带有显式生命周期的可变引用 53 | 54 | let s: &'static str = "I have a static lifetime."; 55 | 56 | // 返回变量的生命周期和至少和y一样长 57 | fn bar<'a, 'b>(x: &'a Foo, y: &'b Foo) -> &'b Foo { 58 | y 59 | } 60 | 61 | fn bar1<'b>(x: &Foo, y: &'b Foo) -> &'b Foo { 62 | y 63 | } 64 | 65 | // 'a:'b,表示'a不短于'b, 只能返回x 66 | fn bar2<'a: 'b, 'b>(x: &'a Foo, y: &'b Foo) -> &'a Foo { 67 | x 68 | // y 69 | } 70 | 71 | // x,y 都可以 72 | fn bar3<'a: 'b, 'b>(x: &'a Foo, y: &'b Foo) -> &'b Foo { 73 | // x 74 | y 75 | } 76 | 77 | // 调用 78 | 79 | let f1 = Foo { 80 | x: 32, 81 | y: (32, true), 82 | z: String::from("rust"), 83 | }; 84 | { 85 | let f2 = Foo { 86 | x: 32, 87 | y: (32, true), 88 | z: String::from("rust"), 89 | }; 90 | 91 | bar(&f1, &f2); 92 | bar1(&f1, &f2); 93 | bar2(&f1, &f2); 94 | bar3(&f1, &f2); 95 | } 96 | 97 | 98 | ``` 99 | */ 100 | 101 | pub fn lifetime_params() { 102 | println!(""); 103 | } 104 | -------------------------------------------------------------------------------- /module-two/src/borrow_lifetime/mod.rs: -------------------------------------------------------------------------------- 1 | //! 2 借用与生命周期 2 | //! 3 | 4 | pub mod borrow_rules; 5 | pub mod lifetime; 6 | pub mod lifetime_params; 7 | -------------------------------------------------------------------------------- /module-two/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc( 2 | html_playground_url = "https://play.rust-lang.org/", 3 | test(no_crate_inject, attr(deny(warnings))), 4 | test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) 5 | )] 6 | 7 | pub mod borrow_lifetime; 8 | pub mod ownership; 9 | pub mod traits; 10 | 11 | 12 | -------------------------------------------------------------------------------- /module-two/src/ownership/dynamic_sized_type.rs: -------------------------------------------------------------------------------- 1 | //! 1.5 动态大小类型与所有权机制 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | // 1 所有权与字符串 8 | 9 | // 我们在前面介绍过,字符串可以存放在程序的只读数据段中或者堆上 10 | // 一般情况下,字符串字面量存放在只读数据段中的,声明之后很少去修改它 11 | // 而需要动态变化的字符串我们会把它存放到堆上,并且通过栈内存来管理堆内存 12 | 13 | let ptr_owner = "Rust"; // 存放在只读数据段中 14 | let heap_ptr_owner = String::from("Rust"); //存放在堆上 15 | 16 | // 1.1 对于存放在只读数据段中的字符串字面量,它的所有权规则和其他基本类型一样,这里不再赘述 17 | 18 | let ptr_copy = ptr_owner; 19 | 20 | // 由于 ptr_owner 和 ptr_copy 的值都是指向相同值的引用,所以它们指向的内存地址是相同的 21 | println!("{:p}", ptr_owner); // 0x10ac12004 22 | println!("{:p}", ptr_copy); // 0x10ac12004 23 | 24 | let mut _heap_ptr_old = String::from("Rust"); //存放在堆上 25 | 26 | let heap_ptr_new = _heap_ptr_old; 27 | 28 | // println!("old owner{:?}", _heap_ptr_old); // 无法再通过 _heap_ptr_old 使用值,因为它已经把数据所有权移交给了新的所有者 heap_ptr_new 29 | println!("new owner{:?}", heap_ptr_new); // heap_ptr_new 可以正常访问到堆上的数据,并且它是唯一的所有者,当它离开作用域时,堆上的数据也会被丢弃 30 | 31 | { 32 | let owner_old = String::from("rust"); 33 | let owner_new = owner_old; 34 | 35 | // 在此处离开作用域 36 | } 37 | 38 | // println!("{:?}", owner_new); 无法再通过 owner_new 使用值,因为它已经被丢弃 39 | 40 | _heap_ptr_old = String::from("Go"); // 重新赋值,注意原变量不能使用是因为转移所有权后被标注为空了,而不是立即被清除了 41 | 42 | // 2 所有权与slice 43 | 44 | // 上面的字符串str 实际上是一个特殊的 slice, 它仅代表有效的utf-8序列 45 | // 而切片中可以包含任何类型的元素,如其他基础类型、自定义类型等, 正如不直接使用 str一样,我们也不直接使用[T],而是使用它的指针(引用)类型,Vec 46 | // slice中的数据也存放在堆上,Rust中slice内存管理逻辑同存放在堆上的str 47 | 48 | // vec 有两种创建方式:使用宏或者方法 49 | let str_slice = vec!["rust", "go", "cpp"]; 50 | let u32_slice: Vec = Vec::new(); 51 | 52 | let new_owner1 = str_slice; 53 | let new_owner2 = u32_slice; 54 | 55 | // println!("{:?}", str_slice); // 无法再通过 str_slice 使用值,因为它已经被丢弃 56 | // println!("{:?}", u32_slice); // 无法再通过 u32_slice 使用值,因为它已经被丢弃 57 | 58 | println!("{:?}", new_owner1); // 可以通过新的所有者访问到原来的值 59 | println!("{:?}", new_owner2); // 可以通过新的所有者访问到原来的值 60 | 61 | // 3 总结 62 | // 当数据存放在堆上时,把所有权赋值给另一个变量,意味着把堆上所有权就会转移给新的所有者,堆上的数据本身没有被复制,原来的所有者不再拥有数据 63 | // 当数据存放在栈上时,把所有权赋值给另一个变量,意味着把栈上的数据复制了一份给新的所有者,原来的所有者仍然拥有原来的数据 64 | 65 | ``` 66 | */ 67 | 68 | pub fn ownership_with_dynamic_sized_types() { 69 | println!(""); 70 | } 71 | -------------------------------------------------------------------------------- /module-two/src/ownership/dynamic_sized_type_intro.rs: -------------------------------------------------------------------------------- 1 | //! 1.4 动态大小类型介绍 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | // 1. &str 9 | let mut a = "rust"; 10 | let size_of_a = std::mem::size_of_val(a); 11 | let ptr_of_a = a.as_ptr(); 12 | 13 | println!("Size of 'rust': {} bytes", size_of_a); // 打印结果:Size of 'rust': 4 bytes 14 | println!("Address of 'rust': {:p}", ptr_of_a); // 打印结果:Address of 'rust': 0x107e52fa0 15 | 16 | a = "go"; 17 | let size_of_a = std::mem::size_of_val(a); 18 | let ptr_of_a = a.as_ptr(); 19 | 20 | println!("Size of 'go': {} bytes", size_of_a); // 打印结果:Size of 'go': 2 bytes 21 | println!("Address of 'go': {:p}", ptr_of_a); // 打印结果:Address of 'go': 0x107e52fdb 22 | 23 | let ptr_of_rust = "rust".as_ptr(); // 访问初始的“rust” 24 | println!("Address of 'rust' after reassignment: {:p}", ptr_of_rust); // 打印结果:Address of 'rust' after reassignment: 0x107e52fa0 25 | 26 | // 2 String 27 | 28 | let mut string_data = String::from("Hello, Rust!"); 29 | let size_of_string = string_data.len(); 30 | let ptr_of_string = string_data.as_ptr(); 31 | 32 | println!("Size of string data: {} bytes", size_of_string); 33 | println!("Address of string data: {:p}", ptr_of_string); 34 | 35 | string_data = String::from("Hello Rust, how are you today?"); 36 | 37 | let size_of_string = string_data.len(); 38 | let ptr_of_string = string_data.as_ptr(); 39 | 40 | println!("Size of string data: {} bytes", size_of_string); 41 | println!("Address of string data: {:p}", ptr_of_string); 42 | 43 | // 3 vec 44 | 45 | let mut vec_data = vec![1]; 46 | let size_of_vec = vec_data.len(); 47 | let ptr_of_vec = vec_data.as_ptr(); 48 | 49 | println!("Size of vector data: {} bytes", size_of_vec); 50 | println!("Address of vector data: {:p}", ptr_of_vec); 51 | 52 | vec_data.push(2); 53 | vec_data.push(3); 54 | vec_data.push(4); 55 | vec_data.push(5); 56 | vec_data.push(6); 57 | vec_data.push(7); 58 | vec_data.push(8); 59 | vec_data.push(9); 60 | 61 | let size_of_vec = vec_data.len(); 62 | let ptr_of_vec = vec_data.as_ptr(); 63 | 64 | println!("Size of vector data: {} bytes", size_of_vec); 65 | println!("Address of vector data: {:p}", ptr_of_vec); 66 | 67 | ``` 68 | */ 69 | 70 | pub fn dynamic_sized_types_intro() { 71 | println!(""); 72 | } 73 | -------------------------------------------------------------------------------- /module-two/src/ownership/mod.rs: -------------------------------------------------------------------------------- 1 | //! 1 所有权机制 2 | //! 3 | 4 | pub mod dynamic_sized_type; 5 | pub mod dynamic_sized_type_intro; 6 | pub mod other_sized_types; 7 | pub mod share_ownership; 8 | pub mod sized_types; 9 | pub mod sized_types_intro; 10 | -------------------------------------------------------------------------------- /module-two/src/ownership/other_sized_types.rs: -------------------------------------------------------------------------------- 1 | //! 1.2 其他固定大小类型 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | use std::mem::size_of; 9 | 10 | 11 | // 整数类型 12 | let int_var: i32 = 10; 13 | println!("Size of integer: {}", size_of::()); // 打印结果:Size of integer: 4 14 | 15 | // 浮点数类型 16 | let float_var: f64 = 10.0; 17 | println!("Size of float: {}", size_of::()); // 打印结果:Size of float: 8 18 | 19 | // 布尔类型 20 | let bool_var: bool = true; 21 | println!("Size of bool: {}", size_of::()); // 打印结果:Size of bool: 1 22 | 23 | // 字符类型 24 | let char_var: char = 'a'; 25 | println!("Size of char: {}", size_of::()); // 打印结果:Size of char: 4 26 | 27 | // 数组类型 28 | let array_var: [i32; 5] = [1, 2, 3, 4, 5]; 29 | println!("Size of array: {}", size_of::<[i32; 5]>()); // 打印结果:Size of array: 20 30 | 31 | // 元组类型 32 | let tuple_var: (i32, f64, bool, char) = (10, 10.0, true, 'a'); 33 | println!("Size of tuple: {}", size_of::<(i32, f64, bool, char)>()); // 打印结果:Size of tuple: 24 34 | 35 | // 引用类型 36 | let ref_var: &i32 = &10; 37 | println!("Size of reference: {}", size_of::<&i32>()); // 打印结果:Size of reference: 8 38 | 39 | // 裸指针类型 40 | let raw_pointer_var: *const i32 = &10; 41 | println!("Size of raw pointer: {}", size_of::<*const i32>()); // 打印结果:Size of raw pointer: 8 42 | 43 | // 函数指针类型 44 | let fn_pointer_var: fn() = foo; 45 | println!("Size of function pointer: {}", size_of::()); // 打印结果:Size of function pointer: 8 46 | 47 | 48 | fn foo() { 49 | println!("This is a function."); 50 | } 51 | 52 | ``` 53 | */ 54 | 55 | pub fn other_sized_types() { 56 | println!(""); 57 | } 58 | -------------------------------------------------------------------------------- /module-two/src/ownership/share_ownership.rs: -------------------------------------------------------------------------------- 1 | //! 1.6 所有权共享 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | // 1 独占访问资源 9 | 10 | let mut dynamic_source = String::from("content"); 11 | 12 | let role1 = dynamic_source; 13 | // let role2 = dynamic_source; // 资源被 role1 所有,此时role1独占访问 14 | let role2 = role1; // 只有role1 把所有权移交给 role2, role2 才可以访问 15 | 16 | // 这样做的好处是,可以避免资源被多个变量同时访问,导致资源被修改 17 | // 坏处是,资源只能被一个变量访问,低效 18 | 19 | use std::rc::Rc; 20 | use std::sync::Arc; 21 | 22 | // 2 所有权与共享容器 Rc,它适用于单线程 23 | 24 | // 使用共享容器包裹动态资源 25 | 26 | let dynamic_source = vec![1, 2]; 27 | 28 | let container = Rc::new(dynamic_source); 29 | 30 | let role1 = container.clone(); // 这里clone方法其实是复制了对资源访问的所有权,而不是资源本身 31 | let role2 = container.clone(); 32 | 33 | // 通过共享容器访问资源,此时资共享资源有三个所有者,可以同时访问 34 | println!("{:?}", container); // [1,2] 35 | println!("{:?}", role1); // [1,2] 36 | println!("{:?}", role2); // [1,2] 37 | 38 | // 3 所有权共享容器 Arc,它适用于多线程 39 | 40 | let dynamic_source = String::from("rust"); 41 | 42 | let container = Arc::new(dynamic_source); 43 | 44 | let role1 = container.clone(); // 这里clone方法其实是复制了对资源访问的所有权,而不是资源本身 45 | let role2 = container.clone(); 46 | 47 | // 通过共享容器访问资源,此时资共享资源有三个所有者,可以同时访问 48 | println!("{:?}", container); // rust 49 | println!("{:?}", role1); // rust 50 | println!("{:?}", role2); // rust 51 | 52 | // 4 共享容器与内存管理 53 | // 注意:Rc和Arc实际上是一种引用计数,每使用clone方法一次,引用计数就会+1,当变量离开作用域时,引用计数会-1,当引用计数为0时,堆内存会被释放 54 | // 整个过程在编译器看来,每个变量都拥有一个Rc或者Arc。所以并不违反所有权规则 55 | // 这里提一点:一般情况下,Rust使用栈来管理堆内存。但是Rc和Arc是一种特别的机制,它允许不受栈内存控制的堆内存,也就是允许内存泄露。对于这种泄漏通过引用计数来管理 56 | 57 | // 4.1 通过栈内存来管理堆内存 58 | 59 | { 60 | let source = String::from("hello"); 61 | 62 | let role1 = source; 63 | println!("{:?}", role1); 64 | // 丢弃 65 | 66 | // println!("{:?}", source); // 不能再使用source,因为source已经移交了所有权 67 | // 当role1离开作用域时,会立即丢弃 role1和堆上的数据 68 | } 69 | 70 | // 4.2 通过引用计数来管理堆内存 71 | 72 | { 73 | let source = String::from("hello"); 74 | 75 | // 使用Rc包裹资源,让堆上资源生命周期更长 76 | let container = Rc::new(source); // 引用计数 + 1 77 | // 78 | let role1 = container.clone(); // 引用计数 + 1 79 | let role2 = container.clone(); // 引用计数 + 1 80 | 81 | // 当变量离开作用域时,role2,role1,container相继离开作用域时,引用计数都会-1,当引用计数为0时,堆上的数据才会被释放 82 | } 83 | 84 | ``` 85 | */ 86 | 87 | pub fn share_ownership() { 88 | println!(""); 89 | } 90 | -------------------------------------------------------------------------------- /module-two/src/ownership/sized_types.rs: -------------------------------------------------------------------------------- 1 | //! 1.3 固定大小类型与所有权 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | // 1 所有权与基本类型 8 | 9 | // 下面的每个值都只有一个所有者 10 | 11 | let num1 = 42; 12 | 13 | let num2 = num1; // num2是一个新的所有者,它的值是 num1值的复制品,num1仍然是一个有效的所有者 14 | println!("{}", num1); // 42,可以通过 num1 使用值 15 | 16 | // 现在有两个值和对应的两个有效的所有者,num1 和 num2 17 | 18 | println!("num1 addr {}", num1); 19 | println!("num2 addr {}", num2); 20 | 21 | // 可以看到值的地址也是不相同(佐证num1和num2各拥有一个值) 22 | // 对于值42来说,它只有一个所有者,因此现在有两个42的值,并且它们的地址是不同的 23 | 24 | println!("num1 addr {:p}", &num1); // 0x7ff7b404dd90 25 | println!("num2 addr {:p}", &num2); // 0x7ff7b404dd94 26 | 27 | let f1 = 42.0; 28 | let b1 = true; 29 | 30 | { 31 | let c1 = '4'; // ‘4’ 这个值的所有者 `c1` 在离开作用域时,值会被丢弃 32 | 33 | let c2 = c1; 34 | 35 | println!("c1 addr {:p}", &c1); // 0x7ff7b404dde8 36 | println!("c2 addr {:p}", &c2); // 0x7ff7b404ddec 37 | } 38 | 39 | // println!("{}", c1) // 无法再使用 owner4,因为它已经被丢弃 40 | 41 | // 2 所有权与复合类型 42 | 43 | let arr1: [i32; 3] = [1, 2, 3]; 44 | let arr2 = arr1; 45 | 46 | println!("arr1 addr {:p}", &arr1); // 0x7ff7b404dd90 47 | println!("arr2 addr {:p}", &arr2); // 0x7ff7b404dd94 48 | 49 | let tuple1 = (32, true, 42.0); 50 | let tuple2 = tuple1; 51 | 52 | println!("tuple1 addr {:p}", &tuple1); // 0x7ff7b404dd91 53 | println!("tuple2 addr {:p}", &tuple2); // 0x7ff7b404dd93 54 | 55 | // 3 所有权与指针类型 56 | 57 | // 这里所说的指针是指指向某个内存地址的变量类型,包括引用、裸指针以及函数指针 58 | 59 | // 3.1 引用 60 | let n = 21; 61 | 62 | let p1 = &n; 63 | let p2 = p1; 64 | 65 | println!("p1 addr {:p}", &p1); // 0x7ff7ba58c938 66 | println!("p2 addr {:p}", &p2); // 0x7ff7ba58c940 67 | 68 | // 3.1 裸指针 69 | // 在rust中使用 `as *const T` 可以将引用转为裸指针 70 | 71 | let num = 32; 72 | 73 | let r_p1 = &num as *const i32; 74 | let r_p2 = r_p1; 75 | 76 | println!("r_p1 addr {:p}", &r_p1); // 0x7ff7b9ecc940 77 | println!("r_p2 addr {:p}", &r_p2); // 0x7ff7b9ecc948 78 | 79 | // 3.2 函数指针 80 | fn add(a: i32, b: i32) -> i32 { 81 | a + b 82 | } 83 | 84 | let f_p1: fn(i32, i32) -> i32 = add; 85 | let f_p2 = f_p1; 86 | 87 | println!("f_p1 addr {:p}", &f_p1); // 0x7ff7b606f9d0 88 | println!("f_p2 addr {:p}", &f_p2); // 0x7ff7b606f9d8 89 | 90 | // 总结:对于固定大小类型而言,讲一个变量的值赋值给另一个变量时,实际上是开辟了新的内存空间,并把值拷贝过来,下面的几种基本类型也同理 91 | 92 | ``` 93 | */ 94 | 95 | pub fn ownership_with_sized_types() { 96 | println!(""); 97 | } 98 | -------------------------------------------------------------------------------- /module-two/src/ownership/sized_types_intro.rs: -------------------------------------------------------------------------------- 1 | //! 1.1 固定大小类型介绍 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | 8 | let mut a: i32 = 32; 9 | 10 | // 获取 'a' 变量的大小(改变前) 11 | let size_before_a = std::mem::size_of_val(&a); 12 | println!("Size of 'a' before change: {} bytes", size_before_a); // 打印结果:Size of 'a' before change: 4 bytes 13 | 14 | // 打印 'a' 变量的地址(改变前) 15 | let address_before_a = &a as *const i32; 16 | println!("Address of 'a' before change: {:?}", address_before_a); 17 | 18 | a = 64; 19 | 20 | // 获取 'a' 变量的大小(改变后) 21 | let size_after_a = std::mem::size_of_val(&a); 22 | println!("Size of 'a' after change: {} bytes", size_after_a); // 打印结果:Size of 'a' after change: 4 bytes 23 | 24 | // 打印 'a' 变量的地址(改变后) 25 | let address_after_a = &a as *const i32; 26 | println!("Address of 'a' after change: {:?}", address_after_a); 27 | 28 | let mut t = ('a', 32, true, 42.1); 29 | 30 | // 获取 't' 变量的大小(改变前) 31 | let size_before_t = std::mem::size_of_val(&t); 32 | println!("Size of 't' before change: {} bytes", size_before_t); // 打印结果:Size of 't' before change: 24 bytes 33 | 34 | // 打印 't' 变量的地址(改变前) 35 | let address_before_t = &t as *const (_, _, _, _); 36 | println!("Address of 't' before change: {:?}", address_before_t); 37 | 38 | t = ('b', 64, false, 84.2); 39 | 40 | // 获取 't' 变量的大小(改变后) 41 | let size_after_t = std::mem::size_of_val(&t); 42 | println!("Size of 't' after change: {} bytes", size_after_t); // 打印结果:Size of 't' after change: 24 bytes 43 | 44 | // 打印 't' 变量的地址(改变后) 45 | let address_after_t = &t as *const (_, _, _, _); 46 | println!("Address of 't' after change: {:?}", address_after_t); 47 | 48 | ``` 49 | */ 50 | 51 | pub fn sized_types_intro() { 52 | println!(""); 53 | } 54 | -------------------------------------------------------------------------------- /module-two/src/traits/mod.rs: -------------------------------------------------------------------------------- 1 | //! 3 trait 2 | //! 3 | 4 | pub mod trait_intro; 5 | pub mod trait_object; 6 | pub mod trait_ownership; 7 | pub mod trait_shared_behavior; 8 | pub mod trait_type_convert; 9 | -------------------------------------------------------------------------------- /module-two/src/traits/trait_intro.rs: -------------------------------------------------------------------------------- 1 | //! 3.1 trait 2 | //! 3 | //! 4 | 5 | /** 6 | 7 | ``` 8 | // 1 trait 种类 9 | 10 | // 1.1 空trait 11 | 12 | trait A {} 13 | 14 | // 1.2 有方法的trait 15 | 16 | trait B { 17 | fn method(&self); 18 | fn method2(&self); 19 | 20 | // ... 21 | } 22 | 23 | // 1.3 有关联类型的trait 24 | 25 | trait C { 26 | type T; 27 | 28 | fn method1(&self) -> Self::T; 29 | } 30 | 31 | // 1.4 有默认实现的trait 32 | 33 | trait D { 34 | // 这个方法是默认实现 35 | fn method1(&self) { 36 | println!("method1"); 37 | } 38 | fn consume_method(&mut self); 39 | } 40 | 41 | // 1.5 有自由方法(函数)的trait 42 | 43 | trait E { 44 | // 这个方法是默认实现 45 | fn method1(&self) { 46 | println!("method1"); 47 | } 48 | // 这个方法需要手动实现 49 | fn method2(&self); 50 | 51 | // 这个方法是默认实现 52 | fn method3() { 53 | println!("freedom method") 54 | } 55 | 56 | // 这个方法需要手动实现 57 | fn method4(a: &str) -> &str; 58 | } 59 | 60 | // 1.6 trait继承 61 | 62 | trait F: E { 63 | // method 64 | } 65 | 66 | // 2 如何实现 trait 67 | 68 | // 2.1 手动实现 69 | 70 | struct Teacher; 71 | 72 | impl Teacher { 73 | fn method1() { 74 | print!("这是类型的关联方法"); 75 | } 76 | } 77 | 78 | Teacher::method1(); // 关联方法调用 79 | 80 | impl A for Teacher {} 81 | 82 | impl B for Teacher { 83 | fn method(&self) { 84 | print!("") 85 | } 86 | fn method2(&self) { 87 | print!("") 88 | } 89 | } 90 | 91 | let mut t = Teacher; 92 | t.method(); // 方法通过实例调用 93 | t.method(); 94 | 95 | impl C for Teacher { 96 | type T = Teacher; 97 | 98 | fn method1(&self) -> Self::T { 99 | let t = String::from("Teacher"); 100 | 101 | // t 102 | Teacher 103 | } 104 | } 105 | 106 | impl D for Teacher { 107 | fn consume_method(&mut self) { 108 | // let x = self; 109 | // let y = self; 110 | } 111 | } 112 | 113 | t.consume_method(); 114 | t.consume_method(); 115 | 116 | impl E for Teacher { 117 | fn method2(&self) {} 118 | fn method4(a: &str) -> &str { 119 | "Rust" 120 | } 121 | } 122 | 123 | Teacher::method4("Go"); // 对trait中自由方法的调用同调用类型的关联方法 124 | 125 | struct Professor; 126 | 127 | // impl F for Professor {} 128 | 129 | impl F for Teacher {} 130 | 131 | // 2.2 使用宏实现 132 | // 标准库和第三方库中一些trait可以通过派生宏来实现 133 | 134 | #[derive(Default, Clone)] 135 | struct Student { 136 | name: String, 137 | age: u32, 138 | } 139 | 140 | // 调用方法 141 | 142 | // 可以直接调用trait提供的方法 143 | let s = Student::default(); 144 | let s1 = s.clone(); 145 | 146 | ``` 147 | */ 148 | 149 | pub fn trait_intro() { 150 | println!(""); 151 | } 152 | -------------------------------------------------------------------------------- /module-two/src/traits/trait_object.rs: -------------------------------------------------------------------------------- 1 | //! 3.2 trait object 2 | //! 3 | //! 4 | 5 | /** 6 | 7 | ``` 8 | // 1 泛型与trait bound 9 | 10 | trait Animal { 11 | fn make_sound(&self) -> &'static str; 12 | } 13 | 14 | trait Food {} 15 | 16 | struct Dog; 17 | 18 | impl Animal for Dog { 19 | fn make_sound(&self) -> &'static str { 20 | "Woof!" 21 | } 22 | } 23 | 24 | struct Cat; 25 | 26 | impl Animal for Cat { 27 | fn make_sound(&self) -> &'static str { 28 | "Meow!" 29 | } 30 | } 31 | 32 | struct Pig; 33 | 34 | impl Animal for Pig { 35 | fn make_sound(&self) -> &'static str { 36 | "Woof!" 37 | } 38 | } 39 | 40 | impl Food for Pig {} 41 | 42 | // trait 作为约束时有三种写法 43 | 44 | fn get_weight(x: T) { 45 | 46 | // do sth 47 | } 48 | 49 | fn get_weight1(x: impl Animal + Food) { 50 | 51 | // do sth 52 | } 53 | 54 | fn get_weight2(x: T) 55 | where 56 | T: Animal + Food, 57 | { 58 | // do sth 59 | } 60 | 61 | let d = Dog; 62 | let c = Cat; 63 | let p = Pig; 64 | 65 | // get_weight(d); 66 | // get_weight(c); 67 | get_weight(p); 68 | 69 | // 2 trait object 70 | // trait 对象通过指针来创建,如 & 或 Box(一种智能指针,可以把数据存放到堆上):&dyn Trait or Box 71 | // Box是Rust中唯一可以把数据强制分配到堆上的类型 72 | 73 | // 静态分发:在编译期通过具体类型实例直接调用方法,编译期单态化 74 | 75 | fn animal_make_sound(a: T) { 76 | a.make_sound(); 77 | } 78 | animal_make_sound(d); 79 | animal_make_sound(c); 80 | 81 | // 动态分发:在运行时先判断类型再查找类型对应方法 82 | // 特别说明,使用 trait object 会带来运行时开销 83 | 84 | fn animal_make_sound2(animals: Vec<&dyn Animal>) { 85 | for animal in animals { 86 | animal.make_sound(); 87 | } 88 | } 89 | 90 | let d = Dog; 91 | let c = Cat; 92 | 93 | let animals: Vec<&dyn Animal> = vec![&d, &c]; 94 | 95 | animal_make_sound2(animals); 96 | 97 | // 3 trait object 安全 98 | // trait中方法返回值类型不为 Self 99 | // trait中方法没有任何泛型类型参数 100 | 101 | pub trait X { 102 | fn method(&self) -> Self; 103 | } 104 | 105 | pub trait Y { 106 | fn print(&self, t: T); 107 | } 108 | 109 | // fn use_trait_object(t: &dyn X) {} 110 | // fn use_trait_object2(t: &dyn Y) {} 111 | 112 | ``` 113 | */ 114 | 115 | pub fn trait_object() { 116 | println!(""); 117 | } 118 | -------------------------------------------------------------------------------- /module-two/src/traits/trait_ownership.rs: -------------------------------------------------------------------------------- 1 | //! 3.4 trait 与所有权 2 | //! 3 | //! 4 | 5 | /** 6 | 7 | ``` 8 | // 1 Copy trait 和 Clone trait 9 | 10 | // 之前我们介绍了所有的固定尺寸类型,当把一个变量赋值给另一个变量时,会发生值的复制 11 | 12 | // owner_one 和 owner_two 现在各自拥有一份值,数据发生了拷贝 13 | let owner_one = 32; 14 | let owner_two = owner_one; 15 | 16 | // 但是对于一些动态尺寸大小的类型,比如str和[T],我们在使用它们的指针 String和Vec时,不会发生值的复制,而是会移交所有权 17 | 18 | let owner_one = String::from("hello"); 19 | let owner_two = owner_one; 20 | 21 | // println!("{:?}", owner_one); // 不可通过owner_one访问数据,因为它已经移交了所有权 22 | 23 | // 从trait的角度来讲,就是所有固定尺寸类型都实现了 Copy 和 Clone trait,而动态尺寸类型都没有实现 Copy trait,但大多都实现了Clone trait 24 | // 并且编译器报错也会告诉你,哪些类型没有实现 Copy trait 25 | 26 | // 如果你想在堆上复制想像使用固定尺寸类型那样一样在堆上复制一份数据,你可以显式调用Clone trait中的 clone方法来实现这一点 27 | 28 | let v = vec![1, 2, 3, 4, 5]; 29 | 30 | let v1 = v.clone(); 31 | let v2 = v.clone(); 32 | let v3 = v1.clone(); 33 | 34 | // 新变量的地址和原变量的地址各不相同 35 | 36 | println!("{:p}", v.as_ptr()); // 0x7fccb3705b30 37 | println!("{:p}", v1.as_ptr()); // 0x7fccb3705b50 38 | println!("{:p}", v2.as_ptr()); // 0x7fccb3705b70 39 | println!("{:p}", v3.as_ptr()); // 0x7fccb3705b90 40 | 41 | // 2 trait实现与所有权 42 | // 在自定义 trait中的方法时,你可以根据需要选择要获取类型的不可变引用、可变引用或者所有权 43 | 44 | trait A { 45 | // 需要手动实现,获取所有权 46 | fn take_ownership(self); 47 | 48 | // 默认实现,获取不可变引用 49 | fn take_ref(&self) { 50 | println!("这个方法获取了类型的不可变引用") 51 | } 52 | 53 | // 默认实现,获取可变引用 54 | fn take_mut(&mut self) { 55 | println!("这个方法获取了类型的可变引用") 56 | } 57 | } 58 | 59 | struct X; 60 | 61 | impl A for X { 62 | fn take_ownership(self) { 63 | println!("这个方法获取了类型的所有权") 64 | } 65 | 66 | // 默认实现不用手动实现 67 | } 68 | 69 | let x = X; 70 | 71 | x.take_ownership(); // 这个方法获取了类型的所有权 72 | // x.take_ref();// 不能再使用x,因为上述方法已经获取了所有权 73 | 74 | let mut y = X; 75 | y.take_ref(); // 这个方法获取了类型的不可变引用 76 | y.take_mut(); // 这个方法获取了类型的可变引用 77 | 78 | // 特别说明:所有权机制和trait本质上是Rust中两个独立的概念,即使没有trait,所有权机制也是成立的(这也是我们在介绍所有权机制时为什么没有提及trait,因为不需要) 79 | // 但trait系统让所有权机制更加的显式化了,更好理解,也更好使用 80 | ``` 81 | */ 82 | 83 | pub fn trait_ownership() { 84 | println!(""); 85 | } 86 | -------------------------------------------------------------------------------- /module-two/src/traits/trait_shared_behavior.rs: -------------------------------------------------------------------------------- 1 | //! 3.3 trait 定义类型共有行为 2 | //! 3 | //! 4 | 5 | /** 6 | 7 | ``` 8 | 9 | pub struct Book { 10 | name: String, 11 | price: f64, 12 | inventory: u32, 13 | author: String, 14 | } 15 | 16 | pub struct Cosmetic { 17 | name: String, 18 | price: f64, 19 | inventory: u32, 20 | } 21 | 22 | pub trait Record { 23 | fn set_price(&mut self, price: f64); 24 | fn set_inventory(&mut self, inventory: u32); 25 | } 26 | 27 | impl Record for Book { 28 | fn set_price(&mut self, price: f64) { 29 | self.price = price; 30 | } 31 | 32 | fn set_inventory(&mut self, inventory: u32) { 33 | self.inventory = inventory; 34 | } 35 | } 36 | 37 | impl Record for Cosmetic { 38 | fn set_price(&mut self, price: f64) { 39 | self.price = price; 40 | } 41 | 42 | fn set_inventory(&mut self, inventory: u32) { 43 | self.inventory = inventory; 44 | } 45 | } 46 | 47 | let mut book = Book { 48 | name: String::from("Book A"), 49 | price: 29.99, 50 | inventory: 10, 51 | author: String::from("Author X"), 52 | }; 53 | 54 | let mut cosmetic = Cosmetic { 55 | name: String::from("Lipstick"), 56 | price: 9.99, 57 | inventory: 50, 58 | }; 59 | 60 | book.set_price(39.99); 61 | book.set_inventory(5); 62 | 63 | cosmetic.set_price(14.99); 64 | cosmetic.set_inventory(20); 65 | 66 | println!( 67 | "Book: {} - Price: {} - Inventory: {} - Author: {}", 68 | book.name, book.price, book.inventory, book.author 69 | ); 70 | println!( 71 | "Cosmetic: {} - Price: {} - Inventory: {}", 72 | cosmetic.name, cosmetic.price, cosmetic.inventory 73 | ); 74 | 75 | ``` 76 | */ 77 | 78 | pub fn trait_shared_behavior() { 79 | println!(""); 80 | } 81 | -------------------------------------------------------------------------------- /module-two/src/traits/trait_type_convert.rs: -------------------------------------------------------------------------------- 1 | //! 3.5 trait 与类型转换 2 | //! 3 | 4 | /** 5 | 6 | ``` 7 | // 1 类型转换trait:From和Into 8 | // Into trait 会自动实现 9 | 10 | // 1.1 From i32 to Number 11 | 12 | use std::convert::From; 13 | 14 | #[derive(Debug)] 15 | struct Number { 16 | value: i32, 17 | } 18 | 19 | // 为自定义类型实现From trait,注意这里Trait带了一个类型参数i32,特指将i32转换为Number 20 | 21 | impl From for Number { 22 | fn from(item: i32) -> Self { 23 | Number { value: item } 24 | } 25 | } 26 | 27 | // 使用From trait中的from方法将i32转换为Number 28 | let num = Number::from(30); 29 | println!("My number is {:?}", num); 30 | 31 | let n: Number = 32.into(); 32 | 33 | // 1.2 From Number to i32 34 | 35 | // 为自定义类型实现Into trait,注意这里Trait带了一个类型参数Number,特指将Number转换为i32 36 | impl From for i32 { 37 | fn from(item: Number) -> Self { 38 | item.value 39 | } 40 | } 41 | 42 | let num = i32::from(32); 43 | let x = Number { value: 10 }; 44 | 45 | // 使用Into trait中的into方法将Number转换为i32 46 | let num: i32 = x.into(); 47 | println!("number is {:?}", num); 48 | 49 | // 与此相似的trait还有 TryFrom 和 TryInto 50 | // 在实际中,TryFrom 和 TryInto 用的比较多,因为它们可以处理错误,但是实现逻辑和 From 和 Into 一样 51 | 52 | // 2 AsRef 和 AsMut 53 | 54 | // 通过AsMut获取可变引用:注意这里获取结构体成员的可变引用 55 | impl AsMut for Number { 56 | fn as_mut(&mut self) -> &mut i32 { 57 | &mut self.value 58 | } 59 | } 60 | 61 | let mut num = Number { value: 30 }; 62 | 63 | let ref_num = num.as_mut(); 64 | 65 | // 通过AsRef获取变量的不可变引用:注意这里获取结构体成员的不可变引用 66 | impl AsRef for Number { 67 | fn as_ref(&self) -> &i32 { 68 | &self.value 69 | } 70 | } 71 | 72 | let num = Number { value: 40 }; 73 | 74 | let ref_num: &i32 = num.as_ref(); 75 | 76 | // 特别说明:以上代码展示并不一定是最佳实践,只是为了介绍知识点而展示的可能性 77 | 78 | ``` 79 | */ 80 | 81 | pub fn trait_type_convert() { 82 | println!(""); 83 | } 84 | -------------------------------------------------------------------------------- /rust.txtr: -------------------------------------------------------------------------------- 1 | accessible -------------------------------------------------------------------------------- /rust_project_example/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "cfg-if" 7 | version = "1.0.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 10 | 11 | [[package]] 12 | name = "entry" 13 | version = "0.1.0" 14 | dependencies = [ 15 | "lib1", 16 | ] 17 | 18 | [[package]] 19 | name = "getrandom" 20 | version = "0.2.10" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 23 | dependencies = [ 24 | "cfg-if", 25 | "libc", 26 | "wasi", 27 | ] 28 | 29 | [[package]] 30 | name = "lib1" 31 | version = "0.1.0" 32 | dependencies = [ 33 | "lib2", 34 | "lib3", 35 | ] 36 | 37 | [[package]] 38 | name = "lib2" 39 | version = "0.1.0" 40 | 41 | [[package]] 42 | name = "lib3" 43 | version = "0.1.0" 44 | dependencies = [ 45 | "rand", 46 | ] 47 | 48 | [[package]] 49 | name = "libc" 50 | version = "0.2.147" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" 53 | 54 | [[package]] 55 | name = "ppv-lite86" 56 | version = "0.2.17" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 59 | 60 | [[package]] 61 | name = "rand" 62 | version = "0.8.5" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 65 | dependencies = [ 66 | "libc", 67 | "rand_chacha", 68 | "rand_core", 69 | ] 70 | 71 | [[package]] 72 | name = "rand_chacha" 73 | version = "0.3.1" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 76 | dependencies = [ 77 | "ppv-lite86", 78 | "rand_core", 79 | ] 80 | 81 | [[package]] 82 | name = "rand_core" 83 | version = "0.6.4" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 86 | dependencies = [ 87 | "getrandom", 88 | ] 89 | 90 | [[package]] 91 | name = "wasi" 92 | version = "0.11.0+wasi-snapshot-preview1" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 95 | -------------------------------------------------------------------------------- /rust_project_example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["entry","lib1","lib2","lib3"] -------------------------------------------------------------------------------- /rust_project_example/entry/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "entry" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | lib1 = {path = "../lib1" } -------------------------------------------------------------------------------- /rust_project_example/entry/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | // use lib1::lib1_type::traits::Lib1Trait; 4 | use lib1::lib1_type::types::create_lib1_struct; 5 | 6 | fn main() { 7 | println!("Hello, world!"); 8 | 9 | create_lib1_struct(); 10 | } 11 | -------------------------------------------------------------------------------- /rust_project_example/lib1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lib1" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | lib2 = {path = "../lib2" } 10 | lib3 = {path = "../lib3" } -------------------------------------------------------------------------------- /rust_project_example/lib1/rust.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/706creators/rust-co-learn/02a2a2141c7fcc577d410c161831138f3ec45bfb/rust_project_example/lib1/rust.txt -------------------------------------------------------------------------------- /rust_project_example/lib1/src/code.rs: -------------------------------------------------------------------------------- 1 | #[allow(dead_code)] 2 | use std::fs::File; 3 | use std::io::Error; 4 | 5 | pub fn read_file(path: &str) -> Result { 6 | // 2.1 读取文件 7 | let file = File::open(path); 8 | 9 | // 2.2 判断文件是否存在 10 | match file { 11 | Ok(file) => Ok(file), 12 | Err(error) => Err(error), 13 | } 14 | } 15 | 16 | #[derive(Debug)] 17 | pub struct Rectangle { 18 | pub width: u32, 19 | pub height: u32, 20 | } 21 | 22 | impl Rectangle { 23 | pub fn can_hold(&self, other: &Rectangle) -> bool { 24 | self.width > other.width && self.height > other.height 25 | } 26 | } 27 | 28 | pub fn add_two(a: i32) -> i32 { 29 | a + 2 30 | } 31 | 32 | pub struct Guess { 33 | value: i32, 34 | } 35 | 36 | impl Guess { 37 | pub fn new(value: i32) -> Guess { 38 | if value < 1 || value > 100 { 39 | panic!("Guess value must be between 1 and 100, got {}.", value); 40 | } 41 | 42 | Guess { value } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /rust_project_example/lib1/src/doc.rs: -------------------------------------------------------------------------------- 1 | /// ``` 2 | /// fn add(a: i32, b: i32) -> i32 { 3 | /// a + b 4 | /// } 5 | /// let result = add(2, 3); 6 | /// assert_eq!(result, 5); 7 | 8 | /// ``` 9 | 10 | fn _add() {} 11 | -------------------------------------------------------------------------------- /rust_project_example/lib1/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[allow(dead_code)] 2 | pub mod code; 3 | mod doc; 4 | pub mod lib1_type; 5 | 6 | // use lib1_type::traits::Lib1_trait;// 测试模块 7 | 8 | // 导出这个函数 9 | pub use my_add::*; 10 | mod my_add { 11 | 12 | pub fn add() -> i32 { 13 | 2 + 2 14 | } 15 | } 16 | 17 | #[cfg(test)] 18 | 19 | mod tests { 20 | use super::*; 21 | use code::add_two; 22 | use code::read_file; 23 | use code::Guess; 24 | use code::Rectangle; 25 | 26 | // 1 使用 assert! 宏断言结果是 true 27 | 28 | #[test] 29 | fn larger_can_hold_smaller() { 30 | let larger = Rectangle { 31 | width: 8, 32 | height: 7, 33 | }; 34 | let smaller = Rectangle { 35 | width: 5, 36 | height: 1, 37 | }; 38 | 39 | assert!(larger.can_hold(&smaller)); // 可以直接断言,也可以带上提示信息 40 | assert!( 41 | larger.can_hold(&smaller), 42 | "larger is {:?}, smaller is {:?}", 43 | larger, 44 | smaller 45 | ); 46 | } 47 | 48 | // 2 使用 assert_eq! 宏断言两个值相等 49 | // 3 使用 assert_ne! 宏断言两个值不相等 50 | 51 | #[test] 52 | fn it_adds_two() { 53 | assert_eq!(4, add_two(2)); 54 | assert_ne!(3, add_two(2)); 55 | } 56 | 57 | // 4 使用 should_panic 宏断言函数会 panic 58 | 59 | #[test] 60 | #[should_panic] 61 | fn greater_than_100() { 62 | Guess::new(200); 63 | } 64 | 65 | // 5 使用Result类型的断言 66 | 67 | #[test] 68 | fn read_file_should_works() -> Result<(), String> { 69 | match read_file("rust.txt") { 70 | Ok(_) => Ok(()), 71 | Err(_) => Err(String::from("file did not exit")), 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /rust_project_example/lib1/src/lib1_type/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod traits; 2 | pub mod types; 3 | -------------------------------------------------------------------------------- /rust_project_example/lib1/src/lib1_type/traits.rs: -------------------------------------------------------------------------------- 1 | pub trait Lib1Trait { 2 | fn new(&self) -> Self; 3 | fn print(&self) { 4 | println!("Hello,it comes from lib1") 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /rust_project_example/lib1/src/lib1_type/types.rs: -------------------------------------------------------------------------------- 1 | #[allow(dead_code)] 2 | use lib2::lib2_type::types::create_lib2_struct; 3 | use lib3::lib3_type::types::create_lib3_struct; 4 | pub struct Lib1Struct { 5 | #[allow(dead_code)] 6 | name: T, 7 | #[allow(dead_code)] 8 | num: i32, 9 | } 10 | 11 | pub fn create_lib1_struct() -> Lib1Struct { 12 | let s = Lib1Struct { 13 | name: String::from("lib1"), 14 | num: 32, 15 | }; 16 | 17 | print!("lib1 struct created! "); 18 | 19 | create_lib2_struct(); 20 | create_lib3_struct(); 21 | 22 | s 23 | } 24 | -------------------------------------------------------------------------------- /rust_project_example/lib1/tests/lib1_test.rs: -------------------------------------------------------------------------------- 1 | use lib1::add; 2 | 3 | #[test] 4 | fn it_adds_two() { 5 | assert_eq!(4, add()); 6 | } 7 | -------------------------------------------------------------------------------- /rust_project_example/lib2/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lib2" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /rust_project_example/lib2/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[allow(dead_code)] 2 | pub mod lib2_type; 3 | -------------------------------------------------------------------------------- /rust_project_example/lib2/src/lib2_type/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | pub mod traits; 3 | pub mod types; 4 | -------------------------------------------------------------------------------- /rust_project_example/lib2/src/lib2_type/traits.rs: -------------------------------------------------------------------------------- 1 | #[allow(dead_code)] 2 | pub trait Lib1Trait { 3 | fn new(&self) -> Self; 4 | fn print(&self) { 5 | println!("Hello,it comes from lib2") 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /rust_project_example/lib2/src/lib2_type/types.rs: -------------------------------------------------------------------------------- 1 | #[allow(dead_code)] 2 | 3 | pub struct Lib2Struct { 4 | name: T, 5 | num: i32, 6 | } 7 | 8 | pub fn create_lib2_struct() -> Lib2Struct { 9 | let s = Lib2Struct { 10 | name: String::from("lib1"), 11 | num: 32, 12 | }; 13 | 14 | print!("lib2 struct created! "); 15 | 16 | s 17 | } 18 | -------------------------------------------------------------------------------- /rust_project_example/lib3/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lib3" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | rand = "0.8.5" 10 | -------------------------------------------------------------------------------- /rust_project_example/lib3/example/example.rs: -------------------------------------------------------------------------------- 1 | use lib3::lib3_type::types::create_lib3_struct; 2 | 3 | fn main() { 4 | create_lib3_struct(); 5 | } 6 | -------------------------------------------------------------------------------- /rust_project_example/lib3/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[allow(dead_code)] 2 | pub mod lib3_type; 3 | -------------------------------------------------------------------------------- /rust_project_example/lib3/src/lib3_type/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | pub mod traits; 4 | pub mod types; 5 | -------------------------------------------------------------------------------- /rust_project_example/lib3/src/lib3_type/traits.rs: -------------------------------------------------------------------------------- 1 | #[allow(dead_code)] 2 | pub trait Lib3Trait { 3 | fn new(&self) -> Self; 4 | fn print(&self) { 5 | println!("Hello,it comes from lib3") 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /rust_project_example/lib3/src/lib3_type/types.rs: -------------------------------------------------------------------------------- 1 | #[allow(dead_code)] 2 | use rand::Rng; 3 | pub struct Lib3Struct { 4 | name: T, 5 | num: i32, 6 | } 7 | 8 | pub fn create_lib3_struct() -> Lib3Struct { 9 | let s = Lib3Struct { 10 | name: String::from("lib1"), 11 | num: 32, 12 | }; 13 | 14 | print!("lib3 struct created! "); 15 | 16 | let mut rng = rand::thread_rng(); 17 | let num: i32 = rng.gen_range(0..10); 18 | println!("Generated random number: {}", num); 19 | 20 | s 21 | } 22 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc( 2 | html_playground_url = "https://play.rust-lang.org/", 3 | test(no_crate_inject, attr(deny(warnings))), 4 | test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) 5 | )] 6 | 7 | //! Rust 共学参考资料 8 | --------------------------------------------------------------------------------