diff --git a/README.md b/README.md index 2fb5e9d1..bbb9b6db 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,6 @@ - [@JesseAtSZ](https://github.com/JesseAtSZ) - [@1132719438](https://github.com/1132719438) - [@Mintnoii](https://github.com/Mintnoii) -- [@mg-chao](https://github.com/mg-chao) -- [@codemystery](https://github.com/codemystery) 尤其感谢这些主要贡献者,谢谢你们花费大量时间贡献了多处`fix`和高质量的内容优化。非常感动,再次感谢~~ diff --git a/src/advance/functional-programing/iterator.md b/src/advance/functional-programing/iterator.md index 10d90de8..af8f0663 100644 --- a/src/advance/functional-programing/iterator.md +++ b/src/advance/functional-programing/iterator.md @@ -355,7 +355,7 @@ impl Counter { } ``` -我们为计数器 `Counter` 实现了一个关联函数 `new`,用于创建新的计数器实例。下面们继续为计数器实现 `Iterator` 特征: +我们为计数器 `Counter` 实现了一个关联函数 `new`,用于创建新的计数器实例。下面我们继续为计数器实现 `Iterator` 特征: ```rust impl Iterator for Counter { diff --git a/src/advance/smart-pointer/deref.md b/src/advance/smart-pointer/deref.md index b5fa4048..7e93f483 100644 --- a/src/advance/smart-pointer/deref.md +++ b/src/advance/smart-pointer/deref.md @@ -1,16 +1,39 @@ # Deref 解引用 +在开始之前,我们先来看一段代码: +```rust +#[derive(Debug)] +struct Person { + name: String, + age: u8 +} -何为智能指针?能不让你写出 ******s 形式的解引用,我认为就是智能: ),智能指针的名称来源,主要就在于它实现了 `Deref` 和 `Drop` 特征,这两个特征可以智能地帮助我们节省使用上的负担: +impl Person { + fn new(name: String, age: u8) -> Self { + Person { name, age} + } + + fn display(self: &mut Person, age: u8) { + let Person{name, age} = &self; + } +} +``` + +以上代码有一个很奇怪的地方:在 `display` 方法中,`self` 是 `&mut Person` 的类型,接着我们对其取了一次引用 `&self`,此时 `&self` 的类型是 `&&mut Person`,然后我们又将其和 `Person` 类型进行匹配,取出其中的值。 + +那么问题来了,Rust 不是号称安全的语言吗?为何允许将 `&&mut Person` 跟 `Person` 进行匹配呢?答案就在本章节中,等大家学完后,再回头自己来解决这个问题 :) 下面正式开始咱们的新章节学习。 + +何为智能指针?能不让你写出 `****s` 形式的解引用,我认为就是智能: ),智能指针的名称来源,主要就在于它实现了 `Deref` 和 `Drop` 特征,这两个特征可以智能地帮助我们节省使用上的负担: - `Deref` 可以让智能指针像引用那样工作,这样你就可以写出同时支持智能指针和引用的代码,例如 `*T` - `Drop` 允许你指定智能指针超出作用域后自动执行的代码,例如做一些数据清除等收尾工作 -下面先来看看 `Deref` 特征是如何工作的。 +先来看看 `Deref` 特征是如何工作的。 ## 通过 `*` 获取引用背后的值 在正式讲解 `Deref` 之前,我们先来看下常规引用的解引用。 + 常规引用是一个指针类型,包含了目标数据存储的内存地址。对常规引用使用 `*` 操作符,就可以通过解引用的方式获取到内存地址对应的数据值: ```rust diff --git a/src/basic/collections/hashmap.md b/src/basic/collections/hashmap.md index 3aace70f..499a3548 100644 --- a/src/basic/collections/hashmap.md +++ b/src/basic/collections/hashmap.md @@ -300,3 +300,8 @@ assert_eq!(hash.get(&42), Some(&"the answer")); > 目前,`HashMap` 使用的哈希函数是 `SipHash`,它的性能不是很高,但是安全性很高。`SipHash` 在中等大小的 `Key` 上,性能相当不错,但是对于小型的 `Key` (例如整数)或者大型 `Key` (例如字符串)来说,性能还是不够好。若你需要极致性能,例如实现算法,可以考虑这个库:[ahash](https://github.com/tkaitchuck/ahash) 最后,如果你想要了解 `HashMap` 更多的用法,请参见本书的标准库解析章节:[HashMap 常用方法](../../std/hashmap.md) + + +## 课后练习 + +> [Rust By Practice](https://zh.practice.rs/collections/hashmap.html),支持代码在线编辑和运行,并提供详细的[习题解答](https://github.com/sunface/rust-by-practice)。 \ No newline at end of file diff --git a/src/basic/collections/vector.md b/src/basic/collections/vector.md index a1090c0c..71b68e0e 100644 --- a/src/basic/collections/vector.md +++ b/src/basic/collections/vector.md @@ -232,3 +232,8 @@ fn main() { 在实际使用场景中,特征对象数组要比枚举数组常见很多,主要原因在于[特征对象](../trait/trait-object.md)非常灵活,而编译器对枚举的限制较多,且无法动态增加类型。 最后,如果你想要了解 `Vector` 更多的用法,请参见本书的标准库解析章节:[`Vector`常用方法](../../std/vector.md) + + +## 课后练习 + +> [Rust By Practice](https://zh.practice.rs/collections/vector.html),支持代码在线编辑和运行,并提供详细的[习题解答](https://github.com/sunface/rust-by-practice)。 \ No newline at end of file diff --git a/src/basic/compound-type/string-slice.md b/src/basic/compound-type/string-slice.md index 8bf44f97..6fcd009e 100644 --- a/src/basic/compound-type/string-slice.md +++ b/src/basic/compound-type/string-slice.md @@ -430,3 +430,4 @@ for b in "中国人".bytes() { > Rust By Practice,支持代码在线编辑和运行,并提供详细的[习题解答](https://github.com/sunface/rust-by-practice)。 > - [字符串](https://zh.practice.rs/compound-types/string.html) > - [切片](https://zh.practice.rs/compound-types/slice.html) +> - [String](https://zh.practice.rs/collections/String.html) \ No newline at end of file diff --git a/src/basic/match-pattern/match-if-let.md b/src/basic/match-pattern/match-if-let.md index 1e95bbd9..78c91390 100644 --- a/src/basic/match-pattern/match-if-let.md +++ b/src/basic/match-pattern/match-if-let.md @@ -28,7 +28,7 @@ fn main() { - `match` 的匹配必须要穷举出所有可能,因此这里用 `_` 来代表未列出的所有可能性 - `match` 的每一个分支都必须是一个表达式,且所有分支的表达式最终返回值的类型必须相同 -- **X | Y**,是逻辑运算符 `或`,代表该分支可以匹配 `X` 也可以匹配 `Y`,只要满足一个即可 +- **X | Y**,类似逻辑运算符 `或`,代表该分支可以匹配 `X` 也可以匹配 `Y`,只要满足一个即可 其实 `match` 跟其他语言中的 `switch` 非常像,`_` 类似于 `switch` 中的 `default`。 @@ -366,4 +366,4 @@ fn main() { ## 课后练习 -> [Rust By Practice](https://zh.practice.rs/pattern-match/match-iflet.html),支持代码在线编辑和运行,并提供详细的[习题解答](https://github.com/sunface/rust-by-practice)。 \ No newline at end of file +> [Rust By Practice](https://zh.practice.rs/pattern-match/match-iflet.html),支持代码在线编辑和运行,并提供详细的[习题解答](https://github.com/sunface/rust-by-practice)。 diff --git a/src/basic/trait/advance-trait.md b/src/basic/trait/advance-trait.md index 03435f63..085723f4 100644 --- a/src/basic/trait/advance-trait.md +++ b/src/basic/trait/advance-trait.md @@ -418,3 +418,8 @@ fn main() { 当然,解决办法还是有的,要不怎么说 Rust 是极其强大灵活的编程语言!Rust 提供了一个特征叫 [`Deref`](https://course.rs/advance/smart-pointer/deref.html),实现该特征后,可以自动做一层类似类型转换的操作,可以将 `Wrapper` 变成 `Vec` 来使用。这样就会像直接使用数组那样去使用 `Wrapper`,而无需为每一个操作都添加上 `self.0`。 同时,如果不想 `Wrapper` 暴漏底层数组的所有方法,我们还可以为 `Wrapper` 去重载这些方法,实现隐藏的目的。 + + +## 课后练习 + +> [Rust By Practice](https://zh.practice.rs/generics-traits/advanced-traits.html),支持代码在线编辑和运行,并提供详细的[习题解答](https://github.com/sunface/rust-by-practice)。 \ No newline at end of file diff --git a/src/basic/trait/trait-object.md b/src/basic/trait/trait-object.md index 1307a6da..7fff2378 100644 --- a/src/basic/trait/trait-object.md +++ b/src/basic/trait/trait-object.md @@ -357,3 +357,8 @@ error[E0038]: the trait `std::clone::Clone` cannot be made into an object ``` 这意味着不能以这种方式使用此特征作为特征对象。 + + +## 课后练习 + +> [Rust By Practice](https://zh.practice.rs/generics-traits/trait-object.html),支持代码在线编辑和运行,并提供详细的[习题解答](https://github.com/sunface/rust-by-practice)。 \ No newline at end of file diff --git a/src/basic/trait/trait.md b/src/basic/trait/trait.md index c7ece8f7..c45ef721 100644 --- a/src/basic/trait/trait.md +++ b/src/basic/trait/trait.md @@ -576,3 +576,8 @@ fn main() { 以上两个例子较为复杂,目的是为读者展示下真实的使用场景长什么样,因此需要读者细细阅读,最终消化这些知识对于你的 Rust 之路会有莫大的帮助。 最后,特征和特征约束,是 Rust 中极其重要的概念,如果你还是没搞懂,强烈建议回头再看一遍,或者寻找相关的资料进行补充学习。如果已经觉得掌握了,那么就可以进入下一节的学习。 + + +## 课后练习 + +> [Rust By Practice](https://zh.practice.rs/generics-traits/traits.html),支持代码在线编辑和运行,并提供详细的[习题解答](https://github.com/sunface/rust-by-practice)。 \ No newline at end of file diff --git a/src/basic/variable.md b/src/basic/variable.md index 4152e0c6..a5306165 100644 --- a/src/basic/variable.md +++ b/src/basic/variable.md @@ -4,7 +4,7 @@ ## 为何要手动设置变量的可变性? -在其它大多数语言中,变量一旦创建,要么是可变的,要么是不可变的(ClojureScript),前者为编程提供了灵活性,后者为编程提供了安全性,而 Rust 比较野,选择了两者我都要,既要灵活性又要安全性。 +在其它大多数语言中,要么只支持声明可变的变量,要么只支持声明不可变的变量( 例如函数式语言 ),前者为编程提供了灵活性,后者为编程提供了安全性,而 Rust 比较野,选择了两者我都要,既要灵活性又要安全性。 能想要学习 Rust,说明我们的读者都是相当有水平的程序员了,你们应该能理解**一切选择皆是权衡**,那么两者都要的权衡是什么呢?这就是 Rust 开发团队为我们做出的贡献,两者都要意味着 Rust 语言底层代码的实现复杂度大幅提升,因此 Salute to The Rust Team! @@ -136,6 +136,8 @@ fn main() { 需要注意的是,使用 `+=` 的赋值语句还不支持解构式赋值。 +> 这里用到了模式匹配的一些语法,如果大家看不懂没关系,可以在学完模式匹配章节后,再回头来看。 + ### 变量和常量之间的差异 变量的值不能更改可能让你想起其他另一个很多语言都有的编程概念:**常量**(_constant_)。与不可变变量一样,常量也是绑定到一个常量名且不允许更改的值,但是常量和变量之间存在一些差异: diff --git a/内容变更记录.md b/内容变更记录.md index 7b1e1208..79a191b8 100644 --- a/内容变更记录.md +++ b/内容变更记录.md @@ -1,6 +1,10 @@ # ChangeLog 记录一些值得注意的变更。 +## 2022-03-09 + +- 在 [Deref 章节](https://course.rs/advance/smart-pointer/deref.html)中新增开篇引导示例,帮助读者更好的理解当前章节 + ## 2022-03-08 - 新增章节: [我们到底需不需要链表](https://course.rs/too-many-lists/do-we-need-it)