From ec3abdda1e1975071a2b8a4a32d1578ddf3a39f8 Mon Sep 17 00:00:00 2001 From: zongzi531 Date: Fri, 25 Feb 2022 12:57:33 +0800 Subject: [PATCH 1/9] Fix typo in lifetime/static.md --- contents/advance/lifetime/static.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contents/advance/lifetime/static.md b/contents/advance/lifetime/static.md index 2b45c47e..16cb6ed9 100644 --- a/contents/advance/lifetime/static.md +++ b/contents/advance/lifetime/static.md @@ -150,7 +150,7 @@ error[E0597]: `s1` does not live long enough | - `s1` dropped here while still borrowed ``` -原因很简单,`s1` 获得不够久,没有满足 `'static` 的生命周期要求。 +原因很简单,`s1` 活得不够久,没有满足 `'static` 的生命周期要求。 ## 使用经验 至此,相信大家对于 `'static` 和 `T: 'static` 也有了清晰的理解,那么我们应该如何使用它们呢? From 007c948a902630a3081142b47871a696357bd289 Mon Sep 17 00:00:00 2001 From: Allan Downey Date: Fri, 25 Feb 2022 22:01:19 +0800 Subject: [PATCH 2/9] fix(crate): update `Package` --- contents/basic/crate-module/crate.md | 28 ++++++++++++++-------------- contents/basic/crate-module/intro.md | 9 +++++---- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/contents/basic/crate-module/crate.md b/contents/basic/crate-module/crate.md index 6210fa4b..09b8bfc8 100644 --- a/contents/basic/crate-module/crate.md +++ b/contents/basic/crate-module/crate.md @@ -1,24 +1,24 @@ -# 包和Package +# 包和 Package 当读者按照章节顺序读到本章时,意味着你已经几乎具备了参与真实项目开发的能力。但是真实项目远比我们之前的 `cargo new` 的默认目录结构要复杂,好在,Rust 为我们提供了强大的包管理工具: -- **Package**:可以用来构建、测试和分享包 -- **工作空间workspace**:对于大型项目,可以进一步将多个包联合在一起,组织成工作空间 -- **包Crate**:一个由多个模块组成的树形结构,可以作为三方库进行分发,也可以生成可执行文件进行运行 -- **模块Module**:可以一个文件多个模块,也可以一个文件一个模块,模块可以被认为是真实项目中的代码组织单元 +- **项目(Package)**:可以用来构建、测试和分享包 +- **工作空间(WorkSpace)**:对于大型项目,可以进一步将多个包联合在一起,组织成工作空间 +- **包(Crate)**:一个由多个模块组成的树形结构,可以作为三方库进行分发,也可以生成可执行文件进行运行 +- **模块(Module)**:可以一个文件多个模块,也可以一个文件一个模块,模块可以被认为是真实项目中的代码组织单元 ## 定义 -其实 `Package` 和包 `crate` 很容易被搞混,甚至在很多书中,这两者都是不分的,但是由于官方对此做了明确的区分,因此我们会在本章节中试图(挣扎着)理清这个概念。 +其实项目 `Package` 和包 `Crate` 很容易被搞混,甚至在很多书中,这两者都是不分的,但是由于官方对此做了明确的区分,因此我们会在本章节中试图(挣扎着)理清这个概念。 -#### 包 crate -对于Rust 而言,包是一个独立的可编译单元,它编译后会生成一个可执行文件或者一个库。 +#### 包 Crate +对于 Rust 而言,包是一个独立的可编译单元,它编译后会生成一个可执行文件或者一个库。 一个包会将相关联的功能打包在一起,使得该功能可以很方便的在多个项目中分享。例如标准库中没有提供但是在三方库中提供的 `rand` 包,它提供了随机数生成的功能,我们只需要将该包通过 `use rand;` 引入到当前项目的作用域中,就可以在项目中使用 `rand` 的功能:`rand::XXX`。 同一个包中不能有同名的类型,但是在不同包中就可以。例如,虽然 `rand` 包中,有一个 `Rng` 特征,可是我们依然可以在自己的项目中定义一个 `Rng`,前者通过 `rand::Rng` 访问,后者通过 `Rng` 访问,对于编译器而言,这两者的边界非常清晰,不会存在引用歧义。 -## Package -鉴于 Rust 团队标新立异的起名传统,以及包的名称被 `crate` 占用,库的名称被 `library` 占用,因此导致我不知道该如何准确的翻译 `Package`,遂决定,不翻译,但是大家可以把它理解为一个项目工程,或者一个微服务工程。 +## 项目 Package +鉴于 Rust 团队标新立异的起名传统,以及包的名称被 `crate` 占用,库的名称被 `library` 占用,经过斟酌, 我们决定将 `Package` 翻译成项目,你也可以理解为工程、软件包。 由于 `Package` 就是一个项目,因此它包含有独立的 `Cargo.toml` 文件,以及因为功能性被组织在一起的一个或多个包。一个 `Package` 只能包含**一个**库(library)类型的包,但是可以包含**多个**二进制可执行类型的包。 @@ -34,12 +34,12 @@ $ ls my-project/src main.rs ``` -这里,Cargo 为我们创建了一个名称是 `my-project` 的 `Package`,同时在其中创建了 `Cargo.toml` 文件,可以看一下该文件,里面并没有提到 `src/main.rs` 作为程序的入口,原因是 Cargo 有一个惯例:**src/main.rs是二进制包的根文件,该二进制包的包名跟所属package相同,在这里都是my-project**,所有的代码执行都从该文件中的 `fn main()` 函数开始。 +这里,Cargo 为我们创建了一个名称是 `my-project` 的 `Package`,同时在其中创建了 `Cargo.toml` 文件,可以看一下该文件,里面并没有提到 `src/main.rs` 作为程序的入口,原因是 Cargo 有一个惯例:**`src/main.rs` 是二进制包的根文件,该二进制包的包名跟所属 `Package` 相同,在这里都是 `my-project`**,所有的代码执行都从该文件中的 `fn main()` 函数开始。 使用 `cargo run` 可以运行该项目,输出:`Hello, world!`。 #### 库 Package -再来创建一个库类型的 `package`: +再来创建一个库类型的 `Package`: ```console $ cargo new my-lib --lib Created library `my-lib` package @@ -66,7 +66,7 @@ error: a bin target must be available for `cargo run` #### 典型的 `Package` 结构 -上面创建的 `Package` 中仅包含 `src/main.rs` 文件,意味着它仅包含一个二进制同名包 `my-project`。如果一个 `Package` 同时拥有 `src/main.rs` 和 `src/lib.rs`,那就意味着它包含两个包:库包和二进制包,这两个包名也都是 `my-project` —— 都与 `package` 同名。 +上面创建的 `Package` 中仅包含 `src/main.rs` 文件,意味着它仅包含一个二进制同名包 `my-project`。如果一个 `Package` 同时拥有 `src/main.rs` 和 `src/lib.rs`,那就意味着它包含两个包:库包和二进制包,这两个包名也都是 `my-project` —— 都与 `Package` 同名。 一个真实项目中典型的 `Package`,会包含多个二进制包,这些包文件被放在 `src/bin` 目录下,每一个文件都是独立的二进制包,同时也会包含一个库包,该包只能存在一个 `src/lib.rs`: ```css @@ -88,7 +88,7 @@ error: a bin target must be available for `cargo run` ``` - 唯一库包:`src/lib.rs` -- 默认二进制包:`src/main.rs`,编译后生成的可执行文件与`package`同名 +- 默认二进制包:`src/main.rs`,编译后生成的可执行文件与 `Package` 同名 - 其余二进制包:`src/bin/main1.rs` 和 `src/bin/main2.rs`,它们会分别生成一个文件同名的二进制可执行文件 - 集成测试文件:`tests` 目录下 - 基准性能测试 `benchmark` 文件:`benches` 目录下 diff --git a/contents/basic/crate-module/intro.md b/contents/basic/crate-module/intro.md index 6c15ebcf..89277a57 100644 --- a/contents/basic/crate-module/intro.md +++ b/contents/basic/crate-module/intro.md @@ -4,13 +4,14 @@ 1. 单个文件过大,导致打开、翻页速度大幅变慢 2. 查询和定位效率大幅降低,类比下,你会把所有知识内容放在一个几十万字的文档中吗? 3. 只有一个代码层次:函数,难以维护和协作,想象一下你的操作系统只有一个根目录,剩下的都是单层子目录会如何:`disaster` -4. 容易滋生Bug +4. 容易滋生 Bug 同时,将大的代码文件拆分成包和模块,还允许我们实现代码抽象和复用:将你的代码封装好后提供给用户,那么用户只需要调用公共接口即可,无需知道内部该如何实现。 因此,跟其它语言一样,Rust 也提供了相应概念用于代码的组织管理: -- Packages:一个 `Cargo` 提供的feature,可以用来构建、测试和分享包 -- 包Crate:一个由多个模块组成的树形结构,可以作为三方库进行分发,也可以生成可执行文件进行运行 -- 模块:可以一个文件多个模块,也可以一个文件一个模块,模块可以被认为是真实项目中的代码组织单元 + +- 项目(Packages):一个 `Cargo` 提供的 `feature`,可以用来构建、测试和分享包 +- 包(Crate):一个由多个模块组成的树形结构,可以作为三方库进行分发,也可以生成可执行文件进行运行 +- 模块(Module):可以一个文件多个模块,也可以一个文件一个模块,模块可以被认为是真实项目中的代码组织单元 下面,让我们一一来学习这些概念以及如何在实践中运用。 From 497998914d0b37178648d38b09f46b586755aeec Mon Sep 17 00:00:00 2001 From: Allan Downey Date: Fri, 25 Feb 2022 22:50:23 +0800 Subject: [PATCH 3/9] fix(errors): dead link --- contents/advance/errors.md | 4 ++-- contents/basic/result-error/intro.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contents/advance/errors.md b/contents/advance/errors.md index 474db78a..ed9b6215 100644 --- a/contents/advance/errors.md +++ b/contents/advance/errors.md @@ -1,5 +1,5 @@ # 错误处理 -在之前的[返回值和错误章节](https://course.rs/basic/result-error/intro.html)中,我们学习了几个重要的概念,例如 `Result` 用于返回结果处理,`?` 用于错误的传播,若大家对此还较为模糊,强烈建议回头温习下。 +在之前的[返回值和错误处理](https://course.rs/basic/result-error/intro.html)章节中,我们学习了几个重要的概念,例如 `Result` 用于返回结果处理,`?` 用于错误的传播,若大家对此还较为模糊,强烈建议回头温习下。 在本章节中一起来看看如何对 `Result` ( `Option` ) 做进一步的处理,以及如何定义自己的错误类型。 @@ -515,7 +515,7 @@ fn render() -> Result> { } ``` -这个方法很简单,在绝大多数场景中,性能也非常够用,但是有一个问题:`Result` 实际上不会限制错误的类型,也就是一个类型就算不实现 `Error` 特征,它依然可以在 `Result` 中作为 `E` 来使用,此时这种特征对象的解决方案就无能为力了。 +这个方法很简单,在绝大多数场景中,性能也非常够用,但是有一个问题:`Result` 实际上不会限制错误的类型,也就是一个类型就算不实现 `Error` 特征,它依然可以在 `Result` 中作为 `E` 来使用,此时这种特征对象的解决方案就无能为力了。 #### 自定义错误类型 与特征对象相比,自定义错误类型麻烦归麻烦,但是它非常灵活,因此也不具有上面的类似限制: diff --git a/contents/basic/result-error/intro.md b/contents/basic/result-error/intro.md index 52f91a76..efc359a7 100644 --- a/contents/basic/result-error/intro.md +++ b/contents/basic/result-error/intro.md @@ -4,7 +4,7 @@ 社会演变至今,这种思想依然没变,甚至来到计算中的微观世界,也是如此。及时、准确的获知系统在发生什么,是程序设计的重中之重。因此能够准确的分辨函数返回值是正确的还是错误的、以及在发生错误时该怎么快速处理,成了程序设计语言的必备功能。 -Go 语言为人诟病的其中一点就是 ***if err != nil {}*** 的大量使用,缺乏一些程序设计的美感,不过我倒是觉得这种简单的方式也有其好处,就是阅读代码时的流畅感很强,你不需要过多的思考各种语法是什么意思。与 Go 语言不同,Rust 博采众家之长,实现了颇具自身色彩的返回值和错误处理体系,本章我们就高屋建瓴地来学习,更加深入的讲解见[此章](../../advance/errors/intro.md). +Go 语言为人诟病的其中一点就是 ***if err != nil {}*** 的大量使用,缺乏一些程序设计的美感,不过我倒是觉得这种简单的方式也有其好处,就是阅读代码时的流畅感很强,你不需要过多的思考各种语法是什么意思。与 Go 语言不同,Rust 博采众家之长,实现了颇具自身色彩的返回值和错误处理体系,本章我们就高屋建瓴地来学习,更加深入的讲解见[错误处理](https://course.rs/advance/errors.html)。 ## Rust的错误哲学 错误对于软件来说是不可避免的,因此一门优秀的编程语言必须有其完整的错误处理哲学。在很多情况下,Rust 需要你承认自己的代码可能会出错,并提前采取行动,来处理这些错误。 From 27d5a8d062b6a692265c2db191570a83eedef578 Mon Sep 17 00:00:00 2001 From: Allan Downey Date: Fri, 25 Feb 2022 23:13:04 +0800 Subject: [PATCH 4/9] Update TOC --- contents/SUMMARY.md | 11 ++++++----- contents/basic/result-error/intro.md | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/contents/SUMMARY.md b/contents/SUMMARY.md index 68a9fd41..3033dbde 100644 --- a/contents/SUMMARY.md +++ b/contents/SUMMARY.md @@ -48,11 +48,11 @@ - [动态数组Vector](basic/collections/vector.md) - [KV存储HashMap](basic/collections/hashmap.md) - [类型转换](basic/converse.md) - - [返回值和异常](basic/result-error/intro.md) + - [返回值和错误处理](basic/result-error/intro.md) - [panic深入剖析!](basic/result-error/panic.md) - [返回值Result和?](basic/result-error/result.md) - [包和模块](basic/crate-module/intro.md) - - [包crate](basic/crate-module/crate.md) + - [包Crate](basic/crate-module/crate.md) - [模块Module](basic/crate-module/module.md) - [使用use引入模块及受限可见性](basic/crate-module/use.md) - [注释和文档](basic/comment.md) @@ -64,8 +64,8 @@ - [&'static 和 T: 'static](advance/lifetime/static.md) - [函数式编程: 闭包、迭代器](advance/functional-programing/intro.md) - - [闭包closure](advance/functional-programing/closure.md) - - [迭代器iterator](advance/functional-programing/iterator.md) + - [闭包Closure](advance/functional-programing/closure.md) + - [迭代器Iterator](advance/functional-programing/iterator.md) - [深入类型](advance/into-types/intro.md) - [newtype 和 类型别名](advance/into-types/custom-type.md) - [Sized 和不定长类型 DST](advance/into-types/sized.md) @@ -252,4 +252,5 @@ - [G-Rust版本说明](appendix/rust-version.md) - [H-Rust更新版本列表](appendix/rust-versions/intro.md) - [1.58](appendix/rust-versions/1.58.md) - - [1.59](appendix/rust-versions/1.59.md) \ No newline at end of file + - [1.59](appendix/rust-versions/1.59.md) + diff --git a/contents/basic/result-error/intro.md b/contents/basic/result-error/intro.md index efc359a7..c9de9379 100644 --- a/contents/basic/result-error/intro.md +++ b/contents/basic/result-error/intro.md @@ -1,4 +1,4 @@ -# 返回和错误处理 +# 返回值和错误处理 飞鸽传书、八百里加急,自古以来,掌权者最需要的就是及时获得对某个事物的信息反馈,在此过程中,也定义了相应的应急处理措施。 @@ -6,7 +6,7 @@ Go 语言为人诟病的其中一点就是 ***if err != nil {}*** 的大量使用,缺乏一些程序设计的美感,不过我倒是觉得这种简单的方式也有其好处,就是阅读代码时的流畅感很强,你不需要过多的思考各种语法是什么意思。与 Go 语言不同,Rust 博采众家之长,实现了颇具自身色彩的返回值和错误处理体系,本章我们就高屋建瓴地来学习,更加深入的讲解见[错误处理](https://course.rs/advance/errors.html)。 -## Rust的错误哲学 +## Rust 的错误哲学 错误对于软件来说是不可避免的,因此一门优秀的编程语言必须有其完整的错误处理哲学。在很多情况下,Rust 需要你承认自己的代码可能会出错,并提前采取行动,来处理这些错误。 Rust 中的错误主要分为两类: From 1bc8e01c3d2d1d930929879c0dbedfc8efae9465 Mon Sep 17 00:00:00 2001 From: Allan Downey Date: Sat, 26 Feb 2022 00:35:13 +0800 Subject: [PATCH 5/9] Update appendix --- contents/appendix/derive.md | 2 +- contents/appendix/difficulties.md | 14 ++++---- contents/appendix/expressions.md | 22 ++++++------ contents/appendix/intro.md | 4 +-- contents/appendix/keywords.md | 2 +- contents/appendix/operators.md | 18 +++++----- contents/appendix/prelude.md | 2 +- contents/appendix/rust-version.md | 43 ++++++++++++------------ contents/appendix/rust-versions/1.58.md | 21 ++++++------ contents/appendix/rust-versions/1.59.md | 8 ++--- contents/appendix/rust-versions/intro.md | 4 +-- 11 files changed, 71 insertions(+), 69 deletions(-) diff --git a/contents/appendix/derive.md b/contents/appendix/derive.md index c639691c..b4b102ac 100644 --- a/contents/appendix/derive.md +++ b/contents/appendix/derive.md @@ -1,4 +1,4 @@ -## 附录 D:可派生的 trait +## 附录 D:派生特征 derive 在本书的各个部分中,我们讨论了可应用于结构体和枚举定义的 `derive` 属性。被 `derive` 标记的对象会自动实现对应的默认特征代码,继承相应的功能。 diff --git a/contents/appendix/difficulties.md b/contents/appendix/difficulties.md index 04593e2c..291c38af 100644 --- a/contents/appendix/difficulties.md +++ b/contents/appendix/difficulties.md @@ -1,11 +1,11 @@ -# F-难点索引 +# 附录 F:难点索引 -不可否认,Rust难点很多,而且知识点也很多,随着时间的进行,或多或少都会对一些难点逐渐模糊,这些难点无法通过目录章节名进行索引,因此集中放在此附录中,进行索引,方便读者朋友查阅。 +不可否认,Rust 难点很多,而且知识点也很多,随着时间的进行,或多或少都会对一些难点逐渐模糊,这些难点无法通过目录章节名进行索引,因此集中放在此附录中,进行索引,方便读者朋友查阅。 | 难点及链接 | 简介 | |----- | ------ | -| [?](../basic/result-error/result.md#传播界的大明星:) | 用于简化错误传播 | -| [()](../basic/base-type/function.md#无返回值) | 单元类型 | -| `!` : [1](../basic/base-type/function.md#永不返回的函数), [2](../advance/custom-type.md#!从不返回类型) | 永不返回 | -| [@](../basic/match-pattern/all-patterns.md#绑定) | 为一个字段绑定另外一个变量 | -| ['a: 'b](../advance/lifetime/advance.md#生命周期约束) | 生命周期约束 | \ No newline at end of file +| [?](https://course.rs/basic/result-error/result.html#传播界的大明星-) | 用于简化错误传播 | +| [()](https://course.rs/basic/base-type/function.html#无返回值) | 单元类型 | +| `!` : [1](https://course.rs/basic/base-type/function.html#永不返回的函数), [2](https://course.rs/advance/into-types/custom-type.html#永不返回类型) | 永不返回 | +| [@](https://course.rs/basic/match-pattern/all-patterns.html#绑定) | 为一个字段绑定另外一个变量 | +| ['a: 'b](https://course.rs/advance/lifetime/advance.html#生命周期约束-hrtb) | 生命周期约束 | diff --git a/contents/appendix/expressions.md b/contents/appendix/expressions.md index 91854525..3ac77473 100644 --- a/contents/appendix/expressions.md +++ b/contents/appendix/expressions.md @@ -1,6 +1,6 @@ -# C-表达式 +# 附录 C:表达式 -在[语句与表达式]章节中,我们对表达式有过介绍,下面对这些常用表达式进行一一说明。 +在[语句与表达式](https://course.rs/basic/base-type/statement-expression.html)章节中,我们对表达式有过介绍,下面对这些常用表达式进行一一说明。 ### 基本表达式 ```rust @@ -8,7 +8,7 @@ let n = 3; let s = "test"; ``` -### if表达式 +### if 表达式 ```rust fn main() { let var1 = 10; @@ -23,9 +23,9 @@ fn main() { } ``` -通过`if`表达式将值赋予`var2`. +通过 `if` 表达式将值赋予 `var2`。 -你还可以在循环中结合`continue`、`break`来使用:` +你还可以在循环中结合 `continue` 、`break` 来使用: ```rust let mut v = 0; for i in 1..10 { @@ -35,10 +35,10 @@ for i in 1..10 { i } } -println!("{}",v); +println!("{}", v); ``` -### if let表达式 +### if let 表达式 ```rust let o = Some(3); let v = if let Some(x) = o { @@ -48,7 +48,7 @@ let v = if let Some(x) = o { }; ``` -### match表达式 +### match 表达式 ```rust let o = Some(3); let v = match o { @@ -57,7 +57,7 @@ let v = match o { }; ``` -### loop表达式 +### loop 表达式 ```rust let mut n = 0; let v = loop { @@ -68,7 +68,7 @@ let v = loop { }; ``` -### 语句块{} +### 语句块 {} ```rust let mut n = 0; let v = { @@ -78,4 +78,4 @@ let v = { n }; println!("{}", v); -``` \ No newline at end of file +``` diff --git a/contents/appendix/intro.md b/contents/appendix/intro.md index 31f59e4f..d8e00028 100644 --- a/contents/appendix/intro.md +++ b/contents/appendix/intro.md @@ -1,5 +1,5 @@ # 附录 -附录中包含了一些Rust常用概念的快速索引,方便你的日常查询使用。 +附录中包含了一些 Rust 常用概念的快速索引,方便你的日常查询使用。 -> 大部分的附录借鉴了Rust Book以及相应的[中文翻译书籍](https://rustwiki.org/zh-CN/book/),但同时做了一些的修改,增加准确性和阅读流畅度 \ No newline at end of file +> 大部分的附录借鉴了 Rust Book 以及相应的 [中文翻译书籍](https://rustwiki.org/zh-CN/book/),但同时做了一些的修改,增加准确性和阅读流畅度 diff --git a/contents/appendix/keywords.md b/contents/appendix/keywords.md index e81fdc7b..bd487f63 100644 --- a/contents/appendix/keywords.md +++ b/contents/appendix/keywords.md @@ -102,4 +102,4 @@ fn main() { 此代码编译没有任何错误。注意 `r#` 前缀需同时用于函数名定义和 `main` 函数中的调用。 -原生标识符允许使用你选择的任何单词作为标识符,即使该单词恰好是保留关键字。 此外,原生标识符允许你使用其它Rust版本编写的库。比如,`try` 在Rust 2015 edition 中不是关键字,却在Rust 2018 edition是关键字。所以如果用2015 edition 编写的库中带有 `try` 函数,在 2018 edition 中调用时就需要使用原始标识符语法,在这里是 `r#try`。 +原生标识符允许使用你选择的任何单词作为标识符,即使该单词恰好是保留关键字。 此外,原生标识符允许你使用其它 Rust 版本编写的库。比如,`try` 在 Rust 2015 edition 中不是关键字,却在 Rust 2018 edition 是关键字。所以如果用 2015 edition 编写的库中带有 `try` 函数,在 2018 edition 中调用时就需要使用原始标识符语法,在这里是 `r#try`。 diff --git a/contents/appendix/operators.md b/contents/appendix/operators.md index 947636c4..251094dc 100644 --- a/contents/appendix/operators.md +++ b/contents/appendix/operators.md @@ -7,9 +7,9 @@ 表 B-1 包含了 Rust 中的运算符、上下文中的示例、简短解释以及该运算符是否可重载。如果一个运算符是可重载的,则该运算符上用于重载的特征也会列出。 -下表中,`expr`是表达式,`ident`是标识符,`type`是类型,`var`是变量,`trait`是特征,`pat`是匹配分支(pattern)。 +下表中,`expr` 是表达式,`ident` 是标识符,`type` 是类型,`var` 是变量,`trait` 是特征,`pat` 是匹配分支(pattern)。 -表 B-1: 运算符 +表 B-1:运算符 | 运算符 | 示例 | 解释 | 是否可重载 | |----------|---------|-------------|---------------| @@ -87,7 +87,7 @@ | `!` | 代表总是空的类型,用于发散函数(无返回值函数) | | `_` | 模式绑定中表示忽略的意思;也用于增强整型字面值的可读性 | -表 B-3展示了模块和对象调用路径的语法。 +表 B-3 展示了模块和对象调用路径的语法。 表 B-3:路径相关语法 @@ -121,7 +121,7 @@ 表 B-5 展示了使用特征约束来限制泛型参数的符号。 -表 B-5: 特征约束 +表 B-5:特征约束 | 符号 | 解释 | |--------|-------------| @@ -134,7 +134,7 @@ 表 B-6 展示了宏以及在一个对象上定义属性的符号。 -表 B-6: 宏与属性 +表 B-6:宏与属性 | 符号 | 解释 | |--------|-------------| @@ -147,7 +147,7 @@ 表 B-7 展示了写注释的符号。 -表 B-7: 注释 +表 B-7:注释 | 符号 | 注释 | |--------|-------------| @@ -160,7 +160,7 @@ 表 B-8 展示了出现在使用元组时的符号。 -表 B-8: 元组 +表 B-8:元组 | 符号 | 解释 | |--------|-------------| @@ -175,7 +175,7 @@ 表 B-9 展示了使用大括号的上下文。 -表 B-9: 大括号 +表 B-9:大括号 | 符号 | 解释 | |---------|-------------| @@ -184,7 +184,7 @@ 表 B-10 展示了使用方括号的上下文。 -表 B-10: 方括号 +表 B-10:方括号 | 符号 | 解释 | |---------|-------------| diff --git a/contents/appendix/prelude.md b/contents/appendix/prelude.md index 2a37c14e..84265e23 100644 --- a/contents/appendix/prelude.md +++ b/contents/appendix/prelude.md @@ -1 +1 @@ -# E-prelude模块 +# 附录 E:prelude 模块 diff --git a/contents/appendix/rust-version.md b/contents/appendix/rust-version.md index 7191f05b..05a4c5b1 100644 --- a/contents/appendix/rust-version.md +++ b/contents/appendix/rust-version.md @@ -1,45 +1,46 @@ # 附录 G:Rust版本发布 -## Rust版本说明 +## Rust 版本说明 早在第一章,我们见过 `cargo new` 在 *Cargo.toml* 中增加了一些有关 `edition` 的元数据。本附录将解释其意义! -与其它语言相比,Rust的更新迭代较为频繁(得益于精心设计过的发布流程以及Rust语言开发者团队管理): -- 每6周发布一个迭代版本 -- 2-3年发布一个新的大版本:Rust 2021 edtion, 每一个版本会结合已经落地的功能,并提供一个清晰的带有完整更新文档和工具的功能包。新版本会作为常规的 6 周发布过程的一部分发布。 +与其它语言相比,Rust 的更新迭代较为频繁(得益于精心设计过的发布流程以及 Rust 语言开发者团队管理): + +- 每 6 周发布一个迭代版本 +- 2 - 3 年发布一个新的大版本:每一个版本会结合已经落地的功能,并提供一个清晰的带有完整更新文档和工具的功能包。新版本会作为常规的 6 周发布过程的一部分发布。 好处在于,可以满足不同的用户群体的需求: -- 对于活跃的Rust用户,他们总是能很快获取到新的语言内容,毕竟,尝鲜是技术爱好者的共同特点:) -- 对于一般的用户,edition的发布会告诉这些用户:Rust语言相比上次大版本发布,有了重大的改进,值得一看 -- 对于Rust语言开发者,可以让他们的工作成果更快的被世人所知,不必锦衣夜行 + +- 对于活跃的 Rust 用户,他们总是能很快获取到新的语言内容,毕竟,尝鲜是技术爱好者的共同特点:) +- 对于一般的用户,edition 的发布会告诉这些用户:Rust 语言相比上次大版本发布,有了重大的改进,值得一看 +- 对于 Rust 语言开发者,可以让他们的工作成果更快的被世人所知,不必锦衣夜行 -在本文档编写时,Rust 已经有三个版本:Rust 2015、2018、2021。本书基于 Rust 2021 edition 编写。 +在本文档编写时,Rust 已经有三个版本:Rust 2015、2018、2021。本书基于 `Rust 2021 edition` 编写。 *Cargo.toml* 中的 `edition` 字段表明代码应该使用哪个版本编译。如果该字段不存在,其默认为 `2021` 以提供后向兼容性。 -每个项目都可以选择不同于默认的 2021 edition 的版本。这样,版本可能会包含不兼容的修改,比如新版本中新增的关键字可能会与老代码中的标识符冲突并导致错误。不过,除非你选择应用这些修改,否则旧代码依然能够被编译,即便你升级了编译器版本。 +每个项目都可以选择不同于默认的 `Rust 2021 edition` 的版本。这样,版本可能会包含不兼容的修改,比如新版本中新增的关键字可能会与老代码中的标识符冲突并导致错误。不过,除非你选择应用这些修改,否则旧代码依然能够被编译,即便你升级了编译器版本。 -所有 Rust 编译器都支持任何之前存在的编译器版本,并可以链接任何支持版本的包。编译器修改只影响最初的解析代码的过程。因此,如果你使用 Rust 2021 而某个依赖使用 Rust 2018,你的项目仍旧能够编译并使用该依赖。反之,若项目使用 Rust 2018 而依赖使用 Rust 2021 亦可工作。 +所有 Rust 编译器都支持任何之前存在的编译器版本,并可以链接任何支持版本的包。编译器修改只影响最初的解析代码的过程。因此,如果你使用 `Rust 2021` 而某个依赖使用 `Rust 2018`,你的项目仍旧能够编译并使用该依赖。反之,若项目使用 `Rust 2018` 而依赖使用 `Rust 2021` 亦可工作。 有一点需要明确:大部分功能在所有版本中都能使用。开发者使用任何 Rust 版本将能继续接收最新稳定版的改进。然而在一些情况,主要是增加了新关键字的时候,则可能出现了只能用于新版本的功能。只需切换版本即可利用新版本的功能。 请查看 [Edition Guide](https://rust-lang-nursery.github.io/edition-guide/) 了解更多细节,这是一个完全介绍版本的书籍,包括如何通过 `cargo fix` 自动将代码迁移到新版本。 -## Rust自身开发流程 - +## Rust 自身开发流程 -本附录介绍 Rust语言自身是如何开发的以及这如何影响作为 Rust 开发者的你。 +本附录介绍 Rust 语言自身是如何开发的以及这如何影响作为 Rust 开发者的你。 ### 无停滞稳定 作为一个语言,Rust **十分** 注重代码的稳定性。我们希望 Rust 成为你代码坚实的基础,假如持续地有东西在变,这个希望就实现不了。但与此同时,如果不能实验新功能的话,在发布之前我们又无法发现其中重大的缺陷,而一旦发布便再也没有修改的机会了。 -对于这个问题我们的解决方案被称为 “无停滞稳定”(“stability without stagnation”),其指导性原则是:无需担心升级到最新的稳定版 Rust。每次升级应该是无痛的,并应带来新功能,更少的 bug 和更快的编译速度。 +对于这个问题我们的解决方案被称为 “无停滞稳定”(“stability without stagnation”),其指导性原则是:无需担心升级到最新的稳定版 Rust。每次升级应该是无痛的,并应带来新功能,更少的 Bug 和更快的编译速度。 ### Choo, Choo! ~~ 小火车发布流程启动 -开发Rust语言是基于一个**火车时刻表**来进行的:所有的开发工作在Master分支上完成,但是发布就像火车时刻表一样,拥有不同的时间,发布采用的软件发布列车模型,被用于思科IOS和等其它软件项目。Rust 有三个 **发布通道**(*release channel*): +开发 Rust 语言是基于一个**火车时刻表**来进行的:所有的开发工作在 Master 分支上完成,但是发布就像火车时刻表一样,拥有不同的时间,发布采用的软件发布列车模型,被用于思科IOS和等其它软件项目。Rust 有三个 **发布通道**(*release channel*): * Nightly * Beta @@ -87,7 +88,7 @@ beta: * - - - - - - - - * stable: * ``` -好的!Rust 1.5 发布了!然而,我们忘了些东西:因为又过了 6 周,我们还需发布 **新版** Rust 的 beta 版,Rust 1.6。所以从 `beta` 生成 `stable` 分支后,新版的 `beta` 分支也再次从 `nightly` 生成: +好的!Rust 1.5 发布了!然而,我们忘了些东西:因为又过了 6 周,我们还需发布 **新版** Rust 的 beta 版,Rust 1.6。所以从 `beta` 分支生成 `stable` 分支后,新版的 `beta` 分支也再次从 `nightly` 生成: ```text nightly: * - - * - - * - - * - - * - - * - * - * @@ -101,7 +102,7 @@ stable: * Rust 每 6 周发布一个版本,如时钟般准确。如果你知道了某个 Rust 版本的发布时间,就可以知道下个版本的时间:6 周后。每 6 周发布版本的一个好的方面是下一班车会来得更快。如果特定版本碰巧缺失某个功能也无需担心:另一个版本很快就会到来!这有助于减少因临近发版时间而偷偷释出未经完善的功能的压力。 -多亏了这个过程,你总是可以切换到下一版本的 Rust 并验证是否可以轻易的升级:如果 beta 版不能如期工作,你可以向 Rust 团队报告并在发布稳定版之前得到修复!beta 版造成的破坏是非常少见的,不过 `rustc` 也不过是一个软件,可能会存在 bug。 +多亏了这个过程,你总是可以切换到下一版本的 Rust 并验证是否可以轻易的升级:如果 beta 版不能如期工作,你可以向 Rust 团队报告并在发布稳定版之前得到修复!beta 版造成的破坏是非常少见的,不过 `rustc` 也不过是一个软件,可能会存在 Bug。 ### 不稳定功能 @@ -113,7 +114,7 @@ Rust 每 6 周发布一个版本,如时钟般准确。如果你知道了某个 ### Rustup 和 Rust Nightly 的职责 -#### 安装Rust Nightly版本 +#### 安装 Rust Nightly 版本 Rustup 使得改变不同发布通道的 Rust 更为简单,其在全局或分项目的层次工作。其默认会安装稳定版 Rust。例如为了安装 nightly: ```text @@ -137,14 +138,14 @@ $ cd ~/projects/needs-nightly $ rustup override set nightly ``` -现在,每次在 *~/需要nightly的项目/*下(在项目的根目录下,也就是Cargo.toml所在的目录) 调用 `rustc` 或 `cargo`,`rustup` 会确保使用 nightly 版 Rust。在你有很多 Rust 项目时大有裨益! +现在,每次在 *~/需要nightly的项目/*下(在项目的根目录下,也就是 `Cargo.toml` 所在的目录) 调用 `rustc` 或 `cargo`,`rustup` 会确保使用 nightly 版 Rust。在你有很多 Rust 项目时大有裨益! ### RFC 过程和团队 那么你如何了解这些新功能呢?Rust 开发模式遵循一个 **Request For Comments (RFC) 过程**。如果你希望改进 Rust,可以编写一个提议,也就是 RFC。 -任何人都可以编写 RFC 来改进 Rust,同时这些 RFC 会被 Rust 团队评审和讨论,他们由很多不同分工的子团队组成。这里是 [Rust 官网上](https://www.rust-lang.org/governance) 所有团队的总列表,其包含了项目中每个领域的团队:语言设计、编译器实现、基础设施、文档等。各个团队会阅读相应的提议和评论,编写回复,并最终达成接受或回绝功能的一致。 +任何人都可以编写 RFC 来改进 Rust,同时这些 RFC 会被 Rust 团队评审和讨论,他们由很多不同分工的子团队组成。这里是 [Rust 官网](https://www.rust-lang.org/governance) 上所有团队的总列表,其包含了项目中每个领域的团队:语言设计、编译器实现、基础设施、文档等。各个团队会阅读相应的提议和评论,编写回复,并最终达成接受或回绝功能的一致。 -如果功能被接受了,在 Rust 仓库会打开一个 issue,人们就可以实现它。实现功能的人可能不是最初提议功能的人!当实现完成后,其会合并到 `master` 分支并位于一个特性开关(feature gate)之后,正如 [不稳定功能](#不稳定功能) 部分所讨论的。 +如果功能被接受了,在 Rust 仓库会打开一个 issue,人们就可以实现它。实现功能的人可能不是最初提议功能的人!当实现完成后,其会合并到 `master` 分支并位于一个特性开关(feature gate)之后,正如[不稳定功能](#不稳定功能) 部分所讨论的。 在稍后的某个时间,一旦使用 nightly 版的 Rust 团队能够尝试这个功能了,团队成员会讨论这个功能在 nightly 中运行的情况,并决定是否应该进入稳定版。如果决定继续推进,特性开关会移除,然后这个功能就被认为是稳定的了!乘着“发布的列车”,最终在新的稳定版 Rust 中出现。 diff --git a/contents/appendix/rust-versions/1.58.md b/contents/appendix/rust-versions/1.58.md index 9fc93229..7f09b614 100644 --- a/contents/appendix/rust-versions/1.58.md +++ b/contents/appendix/rust-versions/1.58.md @@ -1,6 +1,6 @@ -# Rust新版解读 | 1.58 | 重点: 格式化字符串捕获环境中的值 +# Rust 新版解读 | 1.58 | 重点: 格式化字符串捕获环境中的值 -众所周知,Rust小版本发布非常频繁,6周就发布一次,因此通常不会有特别值得普通用户关注的内容,但是这次1.58版本不同,新增了(stable化了)一个非常好用的功能:在格式化字符串时捕获环境中的值。 +众所周知,Rust 小版本发布非常频繁,6 周就发布一次,因此通常不会有特别值得普通用户关注的内容,但是这次 1.58 版本不同,新增了(stable 化了)一个非常好用的功能: **在格式化字符串时捕获环境中的值**。 > Rust 1.58 官方 release doc: [Announcing Rust 1.58.0 | Rust Blog](https://blog.rust-lang.org/2022/01/13/Rust-1.58.0.html) @@ -18,7 +18,7 @@ fn main() { println!("Hello, {person}!", person = p); } ``` -问题倒也不大,但是一旦格式化字符串长了后,就会非常冗余,而在1.58后,我们可以这么写: +问题倒也不大,但是一旦格式化字符串长了后,就会非常冗余,而在 1.58 后,我们可以这么写: ```rust fn get_person() -> String { String::from("sunface") @@ -35,8 +35,9 @@ for (name, score) in get_scores() { println!("{name}: {score:width$.precision$}"); } ``` -但也有局限,它只能捕获普通的变量,对于更复杂的类型(例如表达式),可以先将它赋值给一个变量或使用以前的`name = expression`形式的格式化参数。 -目前除了`panic!`外,其它接收格式化参数的宏,都可以使用新的特性。对于`panic!` 而言,如果还在使用`Rust2015`或`2018`大版本 ,那`panic!("{ident}")`依然会被当成 正常的字符串来处理,同时编译器会给予`warn`提示。而对于`2021版本`,则可以正常使用: +但也有局限,它只能捕获普通的变量,对于更复杂的类型(例如表达式),可以先将它赋值给一个变量或使用以前的 `name = expression` 形式的格式化参数。 + +目前除了 `panic!` 外,其它接收格式化参数的宏,都可以使用新的特性。对于 `panic!` 而言,如果还在使用 `2015版本` 或 `2018版本` 版本 ,那 `panic!("{ident}")` 依然会被当成 正常的字符串来处理,同时编译器会给予 `warn` 提示。而对于 `2021版本` ,则可以正常使用: ```rust fn get_person() -> String { String::from("sunface") @@ -53,9 +54,9 @@ thread 'main' panicked at 'Hello, sunface!', src/main.rs:6:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ``` -## 比unwrap更危险的unwrap_unchecked +## 比 unwrap 更危险的 unwrap_unchecked -在1.58中为`Option`和`Result`新增了`unwrap_unchecked`方法,与`unwrap`遇到错误或者空值直接`panic`不同,`unwrap_unchecked`遇到错误时处理方式糟糕的多: +在 1.58 中为 `Option` 和 `Result` 新增了 `unwrap_unchecked` 方法,与 `unwrap` 遇到错误或者空值直接 `panic` 不同,`unwrap_unchecked` 遇到错误时处理方式糟糕的多: ```rust fn get_num() -> Option { None @@ -72,9 +73,9 @@ fn main() { zsh: segmentation fault cargo run ``` -嗯,段错误了,对比下`panic`,有一种泪流满面的冲动:我要这不安全的方法何用? +嗯,段错误了,对比下 `panic`,有一种泪流满面的冲动:我要这不安全的方法何用? 其实,还真有些用: -- 想要较小的可执行文件时(嵌入式,wasm等),该方法就可以大显身手。因为panic会导致[二进制可执行文件变大不少](https://zhuanlan.zhihu.com/p/445465092) -- 它还可以提高一点性能, 因为编译器可能无法优化掉unwrap的指令分支, 虽然它只会增加区区几条分支预测指令 \ No newline at end of file +- 想要较小的可执行文件时(嵌入式,WASM等),该方法就可以大显身手。因为 `panic` 会导致[二进制可执行文件变大不少](https://zhuanlan.zhihu.com/p/445465092) +- 它还可以提高一点性能, 因为编译器可能无法优化掉 `unwrap` 的指令分支, 虽然它只会增加区区几条分支预测指令 diff --git a/contents/appendix/rust-versions/1.59.md b/contents/appendix/rust-versions/1.59.md index c0274f4f..eaf9570b 100644 --- a/contents/appendix/rust-versions/1.59.md +++ b/contents/appendix/rust-versions/1.59.md @@ -1,4 +1,4 @@ -# Rust新版解读 | 1.59 | 重点: 内联汇编、解构式赋值 +# Rust 新版解读 | 1.59 | 重点: 内联汇编、解构式赋值 Rust 团队于今天凌晨( 2022-02-25 )发布了最新的 1.59 版本,其中最引人瞩目的特性应该就是支持在代码中内联汇编了,一起来看看。 ## 内联汇编( inline assembly ) @@ -107,9 +107,9 @@ wasm-opt = ['-Os'] [github上一个开源仓库](https://github.com/rsadsb/adsb_deku/blob/master/CHANGELOG.md#unreleased)也证明了这一点,总体来看,这个配置的效果是非常显著的! ## 默认关闭增量编译 -1.59.0 版本默认关闭了增量编译的功能(你可以通过环境变量显式地启用:`RUSTC_FORCE_INCREMENTAL=1` ),这会降低已知bug [#94124](https://github.com/rust-lang/rust/issues/94124) 的影响,该 bug 会导致增量编译过程中的反序列化的误和 panic。 +1.59.0 版本默认关闭了增量编译的功能(你可以通过环境变量显式地启用:`RUSTC_FORCE_INCREMENTAL=1` ),这会降低已知 Bug [#94124](https://github.com/rust-lang/rust/issues/94124) 的影响,该 Bug 会导致增量编译过程中的反序列化错误和 `panic`。 -不过大家也不用担心,这个 bug 会在 1.60.0 版本修复,也就是六周后,增量编译会重新设置为默认开启,如果没有意外的话 :) +不过大家也不用担心,这个 Bug 会在 1.60.0 版本修复,也就是 6 周后,增量编译会重新设置为默认开启,如果没有意外的话 :) ## 稳定化的 API 列表 -一些方法和特征实现现在已经可以 stable 中使用,具体见[官方发布说明](https://blog.rust-lang.org/2022/02/24/Rust-1.59.0.html#stabilized-apis) \ No newline at end of file +一些方法和特征实现现在已经可以 stable 中使用,具体见[官方发布说明](https://blog.rust-lang.org/2022/02/24/Rust-1.59.0.html#stabilized-apis) diff --git a/contents/appendix/rust-versions/intro.md b/contents/appendix/rust-versions/intro.md index 56404b25..9259799d 100644 --- a/contents/appendix/rust-versions/intro.md +++ b/contents/appendix/rust-versions/intro.md @@ -1,2 +1,2 @@ -# H-Rust更新版本列表 -本目录包含了Rust历次版本更新的重要内容解读,需要注意,每个版本实际更新的内容要比这里记录的更多,全部内容请访问每节开头的官方链接查看。 \ No newline at end of file +# 附录 H:Rust 更新版本列表 +本目录包含了 Rust 历次版本更新的重要内容解读,需要注意,每个版本实际更新的内容要比这里记录的更多,全部内容请访问每节开头的官方链接查看。 From 444ec2f82bb47833707344ccbb53953a324d1c06 Mon Sep 17 00:00:00 2001 From: Sunface Date: Sat, 26 Feb 2022 09:18:03 +0800 Subject: [PATCH 6/9] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 487aa8e8..0e9d78cb 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,11 @@ 非常感谢本教程的所有贡献者们,正是有了你们,才有了现在的高质量 Rust 教程! -- [@1132719438](https://github.com/1132719438) -- [@JesseAtSZ](https://github.com/JesseAtSZ) - [@AllanDowney](https://github.com/AllanDowney) -- [@mg-chao](https://github.com/mg-chao) +- [@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`和高质量的内容优化。非常感动,再次感谢~~ From b519776943bc8a9be52abe2b6058092f3fd609c4 Mon Sep 17 00:00:00 2001 From: Sunface Date: Sat, 26 Feb 2022 09:20:37 +0800 Subject: [PATCH 7/9] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e9d78cb..7ec58f09 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,11 @@ - 官方: [https://course.rs](https://course.rs) - 国内镜像: [https://book.rust.team](https://book.rust.team) - 知乎: [支持章节内目录跳转,很好用!](https://www.zhihu.com/column/c_1452781034895446017) -- 配套练习题: [https://exercise.rs](https://github.com/sunface/rust-exercise) - 最近修订: 2022-02-25 新增 [Cargo使用指南 - 依赖覆盖](https://zhuanlan.zhihu.com/p/472170018) - QQ交流群:1009730433 +> 官方练习题: [https://exercise.rs](https://github.com/sunface/rust-exercise),质量非常高! + ## 教程简介 **`Rust语言圣经`**涵盖从**入门到精通**所需的 Rust 知识,目录及内容都经过深思熟虑的设计,同时语言生动幽默,行文流畅自如,摆脱技术书籍常有的机器味和晦涩感。 From d1f72b88ebc94937fe5c81fe396b31b1386078c7 Mon Sep 17 00:00:00 2001 From: Sunface Date: Sat, 26 Feb 2022 10:09:30 +0800 Subject: [PATCH 8/9] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7ec58f09..c8a368ae 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ - 最近修订: 2022-02-25 新增 [Cargo使用指南 - 依赖覆盖](https://zhuanlan.zhihu.com/p/472170018) - QQ交流群:1009730433 -> 官方练习题: [https://exercise.rs](https://github.com/sunface/rust-exercise),质量非常高! +> Rust难上手?来试试[Rust By Practice](https://github.com/sunface/rust-practice),这里有最好的示例、练习题和应用实践。 ## 教程简介 From e2129417a7711045d8b0d0857b1c213d921e9ded Mon Sep 17 00:00:00 2001 From: Sunface Date: Sat, 26 Feb 2022 10:09:41 +0800 Subject: [PATCH 9/9] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c8a368ae..b3c32f4f 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ - 最近修订: 2022-02-25 新增 [Cargo使用指南 - 依赖覆盖](https://zhuanlan.zhihu.com/p/472170018) - QQ交流群:1009730433 -> Rust难上手?来试试[Rust By Practice](https://github.com/sunface/rust-practice),这里有最好的示例、练习题和应用实践。 +> Rust难上手?来试试 [Rust By Practice](https://github.com/sunface/rust-practice),这里有最好的示例、练习题和应用实践。 ## 教程简介