diff --git a/book-contents/SUMMARY.md b/book-contents/SUMMARY.md index 94577954..7b2fa9eb 100644 --- a/book-contents/SUMMARY.md +++ b/book-contents/SUMMARY.md @@ -62,7 +62,6 @@ - [包crate](advance/crate-module/crate.md) - [模块Module](advance/crate-module/module.md) - [使用use引入模块及受限可见性](advance/crate-module/use.md) - - [工作空间workspace](advance/crate-module/workspace.md) - [深入类型之newtype和Sized](advance/custom-type.md) - [格式化输出](advance/formatted-output.md) - [智能指针 todo](advance/smart-pointer/intro.md) @@ -87,7 +86,8 @@ - [闭包中奇怪的生命周期](pitfalls/closure-with-lifetime.md) - [可变变量不可变?](pitfalls/the-disabled-mutability.md) - [可变借用失败引发的深入思考](pitfalls/multiple-mutable-references.md) - + - [不太勤快的迭代器](pitfalls/lazy-iterators.md) + - [Rust最佳实践 todo](practice/intro.md) - [一些写代码的技巧 todo](practice/coding-tips.md) - [最佳实践 todo](practice/best-pratice.md) diff --git a/book-contents/advance/crate-module/use.md b/book-contents/advance/crate-module/use.md index ba1cb3d2..c89a5af6 100644 --- a/book-contents/advance/crate-module/use.md +++ b/book-contents/advance/crate-module/use.md @@ -68,7 +68,7 @@ fn main() { ## 避免同名引用 根据上一章节的内容,我们只要保证同一个模块中不存在同名项就行,模块之间、包之间的同名,谁管的着谁啊,话虽如此,一起看看,如果遇到同名的情况该如何处理. -#### 使用模块::函数 +#### 模块::函数 ```rust use std::fmt; use std::io; diff --git a/book-contents/advance/crate-module/workspace.md b/book-contents/advance/crate-module/workspace.md deleted file mode 100644 index 2eef2be0..00000000 --- a/book-contents/advance/crate-module/workspace.md +++ /dev/null @@ -1 +0,0 @@ -# 工作空间workspace diff --git a/book-contents/advance/custom-type.md b/book-contents/advance/custom-type.md index 02105fd7..5f15aa2e 100644 --- a/book-contents/advance/custom-type.md +++ b/book-contents/advance/custom-type.md @@ -228,6 +228,8 @@ Rust需要明确的知道一个特定类型的值占据了多少内存空间, 我们之前已经见过,使用`Box`将一个没有固定大小的特征变成一个有固定大小的特征对象,那能否故技重施,将`str`封装成一个固定大小类型?留个悬念先,我们来看看`Sized`特征。 +> Rust中最常见的`DST`类型: `str`, `[T]`, `dyn Trait` + #### Sized特征 既然动态类型的问题这么大,那么在使用泛型时,Rust如何保证我们的泛型参数是固定大小的类型呢?例如以下泛型函数: ```rust diff --git a/book-contents/advance/functional-programing/iterator.md b/book-contents/advance/functional-programing/iterator.md index cb22164d..209bd5dd 100644 --- a/book-contents/advance/functional-programing/iterator.md +++ b/book-contents/advance/functional-programing/iterator.md @@ -395,6 +395,7 @@ println!("{}", val); ``` ## 迭代器的性能 +@todo ## 学习其它方法 迭代器用的好不好,就在于你是否掌握了它的常用方法,且能活学活用,因此多多看看[标准库](https://doc.rust-lang.org/std/iter/trait.Iterator.html)是有好处的,只有知道有什么方法,在需要的时候你才能知道该用什么,就和算法学习一样。 diff --git a/book-contents/advance/global-variable.md b/book-contents/advance/global-variable.md index 4eb033ca..84cd5b36 100644 --- a/book-contents/advance/global-variable.md +++ b/book-contents/advance/global-variable.md @@ -36,4 +36,7 @@ impl Factory{ } } } -``` \ No newline at end of file +``` + +## 从函数中返回全局变量 +https://www.reddit.com/r/learnrust/comments/rqn74g/cant_a_function_return_a_reference_to_some_global/ \ No newline at end of file diff --git a/book-contents/advance/multi-threads/ref-counter-lock.md b/book-contents/advance/multi-threads/ref-counter-lock.md index 9d6f2687..d96bc890 100644 --- a/book-contents/advance/multi-threads/ref-counter-lock.md +++ b/book-contents/advance/multi-threads/ref-counter-lock.md @@ -1 +1,3 @@ # Rc、Arc、Mutex、Rwlock(todo) + +https://oribenshir.github.io/afternoon_rusting//blog/deref-smart-pointer \ No newline at end of file diff --git a/book-contents/basic/comment.md b/book-contents/basic/comment.md index 8ca3168b..a8a8b351 100644 --- a/book-contents/basic/comment.md +++ b/book-contents/basic/comment.md @@ -1 +1,9 @@ -# 文档注释 todo +# 注释及文档 +Rust有一点特别 + + + +## 文档注释查看 +https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#making-useful-documentation-comments + +## 文档注释中写测试 \ No newline at end of file diff --git a/book-contents/pitfalls/lazy-iterators.md b/book-contents/pitfalls/lazy-iterators.md new file mode 100644 index 00000000..10fcb875 --- /dev/null +++ b/book-contents/pitfalls/lazy-iterators.md @@ -0,0 +1,112 @@ +# 不太勤快的迭代器 +迭代器,在Rust中是一个非常耀眼的存在,它光鲜亮丽,它让Rust大道至简,它备受用户的喜爱。可是,它也是懒惰的,不信?一起来看看。 + +## for循环 vs 迭代器 +在迭代器学习中,我们提到过迭代器在功能上可以替代循环,性能上略微优于循环(避免边界检查),安全性上优于循环,因此在Rust中,迭代器往往都是更优的选择,前提是迭代器得发挥作用。 + +在下面代码中,分别是使用`for`循环和迭代器去生成一个`HashMap`。 + +使用循环: +```rust +use std::collections::HashMap; +#[derive(Debug)] +struct Account { + id: u32, +} + +fn main() { + let accounts = [Account { id: 1 }, Account { id: 2 }, Account { id: 3 }]; + + let mut resolvers = HashMap::new(); + for a in accounts { + resolvers.entry(a.id).or_insert(Vec::new()).push(a); + } + + println!("{:?}",resolvers); +} +``` + +使用迭代器: +```rust +let mut resolvers = HashMap::new(); +accounts.into_iter().map(|a| { + resolvers + .entry(a.id) + .or_insert(Vec::new()) + .push(a); +}); +println!("{:?}",resolvers); +``` + +#### 预料之外的结果 +两端代码乍一看(很多时候我们快速浏览代码的时候,不会去细看)都很正常, 运行下试试: + +- `for`循环很正常,输出`{2: [Account { id: 2 }], 1: [Account { id: 1 }], 3: [Account { id: 3 }]}` +- 迭代器很。。。不正常,输出了一个`{}`, 黑人问号`? ?` **?** + +在继续深挖之前,我们先来简单回顾下迭代器。 + +## 回顾下迭代器 +在迭代器章节中,我们曾经提到过,迭代器的[适配器](../advance/functional-programing/iterator.md#消费者与适配器)分为两种:消费者适配器和迭代器适配器,前者用来将一个迭代器变为指定的集合类型,往往通过`collect`实现;后者用于生成一个新的迭代器,例如上例中的`map`。 + +还提到过非常重要的一点: **迭代器适配器都是懒惰的,只有配合消费者适配器使用时,才会进行求值**. + +## 懒惰是根因 +在我们之前的迭代器示例中,只有一个迭代器适配器`map`: +```rust +accounts.into_iter().map(|a| { + resolvers + .entry(a.id) + .or_insert(Vec::new()) + .push(a); +}); +``` + +首先, `accounts`被拿走所有权后转换成一个迭代器,其次该迭代器通过`map`方法生成一个新的迭代器,最后,在此过程中没有以类如`collect`的消费者适配器收尾。 + +因此在上述过程中,`map`完全是懒惰的,它没有做任何事情,它在等一个消费者适配器告诉它:赶紧起床,任务可以开始了,它才会开始行动。 + +自然,我们的插值计划也失败了。 + +> 事实上,IDE和编译器都会对这种代码给出警告:iterators are lazy and do nothing unless consumed + +## 解决办法 +原因非常清晰,如果读者还有疑惑,建议深度下上面给出的迭代器链接,我们这里就不再赘述。 + +下面列出三种合理的解决办法: + +1. 不再使用迭代器适配器`map`,改成`for_each`: +```rust +let mut resolvers = HashMap::new(); +accounts.into_iter().for_each(|a| { + resolvers + .entry(a.id) + .or_insert(Vec::new()) + .push(a); +}); +``` + +但是,相关的文档也友善的提示了我们,除非作为链式调用的收尾,否则更建议使用`for`循环来处理这种情况。哎,忙忙碌碌,又回到了原点,不禁让人感叹:天道有轮回。 + +2. 使用消费者适配器`collect`来收尾,将`map`产生的迭代器收集成一个集合类型: +```rust +let resolvers: HashMap<_, _> = accounts +.into_iter() +.map(|a| (a.id, a)) +.collect(); +``` + +嗯,还挺简洁,挺`rusty`. + +3. 使用`fold`,语义表达更强: +```rust +let resolvers = account.into_iter().fold(HashMap::new(), |mut resolvers, a|{ + resolvers.entry(a.id).or_insert(Vec::new).push(a); + resolvers +}); +``` + +## 总结 +在使用迭代器时,要清晰的认识到需要用到的方法是迭代型还是消费型适配器,如果一个调用链中没有以消费型适配器结尾,就需要打起精神了,也许,不远处就是一个陷阱在等你跳:) + + diff --git a/writing-material/posts/SIMD.md b/writing-material/posts/SIMD.md new file mode 100644 index 00000000..b9c7fb5b --- /dev/null +++ b/writing-material/posts/SIMD.md @@ -0,0 +1,2 @@ + +https://www.reddit.com/r/rust/comments/rqgwaz/why_is_my_simd_code_slower_than_the_naive_one/ \ No newline at end of file diff --git a/writing-material/posts/wasm.md b/writing-material/posts/wasm.md new file mode 100644 index 00000000..e69de29b