Updated src/ALL.md.

This commit is contained in:
Hector PENG 2025-01-10 07:35:51 +08:00
parent c7d90566b5
commit 1f15d567a9
107 changed files with 536 additions and 0 deletions

6
append_end.sh Normal file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
PWD="$(pwd)"
for f in $(find "src/" -type f -name "*.md" ); do
if [[ "${f}" == *"SUMMARY"* ]] || [[ "${f}" == *"README"* ]]; then continue; fi
echo -e "\n\nEnd\n\n" >> "$PWD/$f"
done

View File

@ -7,3 +7,8 @@
This URL is invalid, sorry. Please use the navigation bar or search to continue. It will be redirected to home in <span class="sec-count" style="font-style: italic;font-weight:bold;font-size:large;">n</span> seconds... This URL is invalid, sorry. Please use the navigation bar or search to continue. It will be redirected to home in <span class="sec-count" style="font-style: italic;font-weight:bold;font-size:large;">n</span> seconds...
End

View File

@ -115,3 +115,8 @@ Rust 语言希望也能支持许多其他用户;这里提到的只是一些最
## 本书的源码 ## 本书的源码
本书所产生的源码,可在 [Github: gnu4cn/rust-lang](https://github.com/gnu4cn/rust-lang-zh_CN/releases/tag/v0.2.0) 下载到。 本书所产生的源码,可在 [Github: gnu4cn/rust-lang](https://github.com/gnu4cn/rust-lang-zh_CN/releases/tag/v0.2.0) 下载到。
End

View File

@ -7,3 +7,8 @@
- 编写一个打印出 `Hello, world!` 的程序; - 编写一个打印出 `Hello, world!` 的程序;
- 使用 Rust 的包管理器与构建系统 Cargo 。 - 使用 Rust 的包管理器与构建系统 Cargo 。
End

View File

@ -835,3 +835,8 @@ fn main() {
这个项目以实践的方式,向咱们介绍了许多新的 Rust 概念:`let`、`match`、函数、外部代码箱的使用等等。在接下来的几章中,咱们将更详细地了解这些概念。第 3 章涵盖了大多数编程语言都有的概念,如变量、数据类型和函数等,并展示了如何在 Rust 中使用他们。第 4 章探讨了所有权,这是 Rust 不同于其他语言的一个特性。第 5 章会讨论结构体和方法语法,第 6 章解释了枚举的工作原理。 这个项目以实践的方式,向咱们介绍了许多新的 Rust 概念:`let`、`match`、函数、外部代码箱的使用等等。在接下来的几章中,咱们将更详细地了解这些概念。第 3 章涵盖了大多数编程语言都有的概念,如变量、数据类型和函数等,并展示了如何在 Rust 中使用他们。第 4 章探讨了所有权,这是 Rust 不同于其他语言的一个特性。第 5 章会讨论结构体和方法语法,第 6 章解释了枚举的工作原理。
End

View File

@ -10,3 +10,8 @@
> **关键字keywords** > **关键字keywords**
> >
> 与其他语言一样Rust 语言也有一套仅供这门语言使用的 *关键字keywords*。请记住,咱们不能将这些关键字,用作变量或函数的名字。大多数关键字,都有特殊含义,而咱们将在咱们的 Rust 程序中,使用他们完成各种任务;少数关键字目前没有与其相关的功能,但已被保留用于将来可能添加到 Rust 中的功能。咱们可以在 [附录 A](appendix/keywords.md) 中,找到这些关键字的列表。 > 与其他语言一样Rust 语言也有一套仅供这门语言使用的 *关键字keywords*。请记住,咱们不能将这些关键字,用作变量或函数的名字。大多数关键字,都有特殊含义,而咱们将在咱们的 Rust 程序中,使用他们完成各种任务;少数关键字目前没有与其相关的功能,但已被保留用于将来可能添加到 Rust 中的功能。咱们可以在 [附录 A](appendix/keywords.md) 中,找到这些关键字的列表。
End

View File

@ -3,3 +3,8 @@
**Understanding Ownership** **Understanding Ownership**
所有权是 Rust 最独特的特性,对语言的其他部分有着深刻的影响。他使 Rust 可以在不需要垃圾回收器的情况下,保证内存安全,因此了解所有权的工作原理非常重要。在本章中,我们将讨论所有权,以及几个相关特性:借用、切片,与 Rust 如何将数据放置于内存中。 所有权是 Rust 最独特的特性,对语言的其他部分有着深刻的影响。他使 Rust 可以在不需要垃圾回收器的情况下,保证内存安全,因此了解所有权的工作原理非常重要。在本章中,我们将讨论所有权,以及几个相关特性:借用、切片,与 Rust 如何将数据放置于内存中。
End

View File

@ -5,3 +5,8 @@
结构体,`struct`,或 *structure*,是一种自定义数据类型,允许咱们将多个构成一个有意义的组的相关值,打包在一起并取个名字。如果咱们熟悉某门面向对象的语言,那么一个 `struct` 就像是某个对象的数据属性。在本章中,我们把元组与结构体进行对比,以在咱们已有知识的基础上,说明结构体在何时是更好的数据组织方式。 结构体,`struct`,或 *structure*,是一种自定义数据类型,允许咱们将多个构成一个有意义的组的相关值,打包在一起并取个名字。如果咱们熟悉某门面向对象的语言,那么一个 `struct` 就像是某个对象的数据属性。在本章中,我们把元组与结构体进行对比,以在咱们已有知识的基础上,说明结构体在何时是更好的数据组织方式。
我们将演示如何定义和实例化结构体。我们将讨论如何定义关联函数,尤其是称为 *方法methods* 的关联函数,以指定出与某个结构体类型相关的行为。结构体和枚举(会在第 6 章中讨论),是在咱们程序域中,创建出新类型,以充分利用 Rust 的编译时类型检查的两个基本构建模块。 我们将演示如何定义和实例化结构体。我们将讨论如何定义关联函数,尤其是称为 *方法methods* 的关联函数,以指定出与某个结构体类型相关的行为。结构体和枚举(会在第 6 章中讨论),是在咱们程序域中,创建出新类型,以充分利用 Rust 的编译时类型检查的两个基本构建模块。
End

View File

@ -4,3 +4,8 @@
在本章中,我们将介绍 *枚举enumerations*,也称为 *枚举enums*。枚举允许咱们,通过枚举出其可能的 *变种variants*,来定义某种类型。首先,我们将定义并使用一个枚举,以展示枚举如何与数据一起,编码意义。接下来,我们将探究一个名为 `Option` 的特别有用的枚举,他表示某个值可以是某物,也可以是无。然后,我们将了解 `match` 表达式中的模式匹配,如何使我们可以轻松地针对枚举的不同值,运行不同代码。最后,我们将介绍 `if let` 结构,怎样成为咱们代码中,处理枚举的另一方便简洁的习惯用法。 在本章中,我们将介绍 *枚举enumerations*,也称为 *枚举enums*。枚举允许咱们,通过枚举出其可能的 *变种variants*,来定义某种类型。首先,我们将定义并使用一个枚举,以展示枚举如何与数据一起,编码意义。接下来,我们将探究一个名为 `Option` 的特别有用的枚举,他表示某个值可以是某物,也可以是无。然后,我们将了解 `match` 表达式中的模式匹配,如何使我们可以轻松地针对枚举的不同值,运行不同代码。最后,我们将介绍 `if let` 结构,怎样成为咱们代码中,处理枚举的另一方便简洁的习惯用法。
End

View File

@ -24,3 +24,8 @@ Rust 有数项特性,可以让咱们管理咱们代码的组织,包括哪些
在本章中,我们将介绍所有这些功能,讨论他们如何交互,并探讨如何使用他们来管理作用域。到本章结束时,咱们应对模组系统有扎实的了解,并能像专业人士一样,使用作用域! 在本章中,我们将介绍所有这些功能,讨论他们如何交互,并探讨如何使用他们来管理作用域。到本章结束时,咱们应对模组系统有扎实的了解,并能像专业人士一样,使用作用域!
End

View File

@ -11,3 +11,8 @@ Rust 标准库中包含了几种名为 *集合collections* 的有用数据
要了解由标准库所提供的其他类别集合,请参阅 [文档](https://doc.rust-lang.org/std/collections/index.html)。 要了解由标准库所提供的其他类别集合,请参阅 [文档](https://doc.rust-lang.org/std/collections/index.html)。
这里将讨论怎样创建与更新矢量、字符串与哈希映射,同时会讨论他们因何而变得特殊。 这里将讨论怎样创建与更新矢量、字符串与哈希映射,同时会讨论他们因何而变得特殊。
End

View File

@ -5,3 +5,8 @@
Rust 将错误分组为两个主要类别: *可恢复recoverable**不可恢复unrecoverable* 错误。对于可恢复错误,比如 *文件未找到* 错误,大多数情况下只要将该故障汇报给用户,并重试该操作。而不可恢复错误则总是代码错误的表征,像是尝试访问超出数组末端的某个位置,进而因此就要立即停止该程序。 Rust 将错误分组为两个主要类别: *可恢复recoverable**不可恢复unrecoverable* 错误。对于可恢复错误,比如 *文件未找到* 错误,大多数情况下只要将该故障汇报给用户,并重试该操作。而不可恢复错误则总是代码错误的表征,像是尝试访问超出数组末端的某个位置,进而因此就要立即停止该程序。
大多数语言都没有区分这两种错误而以同样方式使用诸如异常的机制处理这两种错误。Rust 没有异常。相反Rust 有着用于可恢复错误的类型 `Result<T, E>`,以及在程序发生了不可恢复错误时,停止程序执行的 `panic!`the `panic!` macro。本章将首先涵盖对 `panic!` 的调用,并在随后讲解那些返回的 `Result<T, E>` 值。此外,这里会对在决定是否要尝试从错误中恢复,还是要停止程序的执行时的诸多考虑,进行探讨。 大多数语言都没有区分这两种错误而以同样方式使用诸如异常的机制处理这两种错误。Rust 没有异常。相反Rust 有着用于可恢复错误的类型 `Result<T, E>`,以及在程序发生了不可恢复错误时,停止程序执行的 `panic!`the `panic!` macro。本章将首先涵盖对 `panic!` 的调用,并在随后讲解那些返回的 `Result<T, E>` 值。此外,这里会对在决定是否要尝试从错误中恢复,还是要停止程序的执行时的诸多考虑,进行探讨。
End

View File

@ -120,3 +120,8 @@ fn main() {
接下来,就要在泛型下,使用这些同样步骤来降低代码重复了。与函数体可以在抽象的 `list` 而非具体值上运作的方式一样,泛型实现了代码在抽象类型上的操作。 接下来,就要在泛型下,使用这些同样步骤来降低代码重复了。与函数体可以在抽象的 `list` 而非具体值上运作的方式一样,泛型实现了代码在抽象类型上的操作。
比如,假设说这里有两个函数:一个时在 `i32` 值的切片中,找出极大项,而另一个是在 `char` 值的切片中,找出极大项。那该怎样消除重复呢?下面就来解决这个问题! 比如,假设说这里有两个函数:一个时在 `i32` 值的切片中,找出极大项,而另一个是在 `char` 值的切片中,找出极大项。那该怎样消除重复呢?下面就来解决这个问题!
End

View File

@ -9,3 +9,8 @@
可编写出进行假定的一些测试来,比如,在将 `3` 传递给这个 `add_two` 函数时,返回的值就是 `5`。每当修改了代码时,就都可以运行这些测试,来确保车关系的任何既有正确行为,没有发生变化。 可编写出进行假定的一些测试来,比如,在将 `3` 传递给这个 `add_two` 函数时,返回的值就是 `5`。每当修改了代码时,就都可以运行这些测试,来确保车关系的任何既有正确行为,没有发生变化。
测试是门综合技能:尽管这里无法在一章中,涉及到怎样编写良好测试的方方面面,这里还是会对 Rust 各种测试设施的机制进行讨论。这里会讲到在编写测试时可用的注解与宏运行测试的默认动作与选项以及怎样将一些测试组织为单元测试与集成测试unit tests and integration tests 测试是门综合技能:尽管这里无法在一章中,涉及到怎样编写良好测试的方方面面,这里还是会对 Rust 各种测试设施的机制进行讨论。这里会讲到在编写测试时可用的注解与宏运行测试的默认动作与选项以及怎样将一些测试组织为单元测试与集成测试unit tests and integration tests
End

View File

@ -17,3 +17,8 @@ Rust 的速度、安全性、单一二进制可执行程序输出,还有跨平
- 编写测试([第 11 章](Ch11_Writing_Automated_Tests.md) - 编写测试([第 11 章](Ch11_Writing_Automated_Tests.md)
这里还会简要对闭包、迭代器及特质对象等,进行简要介绍,后面的 [第 13 章](Ch13_Functional_Languages_Features_Iterator_and_Closures.md) 与 [第 17 章](Object_Oriented_Programming_Features_of_Rust.md) 等章节,将详细讲解到这些特性。 这里还会简要对闭包、迭代器及特质对象等,进行简要介绍,后面的 [第 13 章](Ch13_Functional_Languages_Features_Iterator_and_Closures.md) 与 [第 17 章](Object_Oriented_Programming_Features_of_Rust.md) 等章节,将详细讲解到这些特性。
End

View File

@ -12,3 +12,8 @@ Rust 的设计曾受到许多现有的语言和技术的启发,而一个显著
- 闭包与迭代器的性能问题(剧透警告:他们比咱们可能想的要快!)。 - 闭包与迭代器的性能问题(剧透警告:他们比咱们可能想的要快!)。
咱们已经讲到过其他的一些 Rust 特性,诸如模式匹配与枚举等,也是受函数式编程影响的。由于掌握闭包与迭代器,是编写惯用、快速 Rust 代码的重要方面,因此咱们将把这整章,都用来讲解他们。 咱们已经讲到过其他的一些 Rust 特性,诸如模式匹配与枚举等,也是受函数式编程影响的。由于掌握闭包与迭代器,是编写惯用、快速 Rust 代码的重要方面,因此咱们将把这整章,都用来讲解他们。
End

View File

@ -12,3 +12,8 @@
相比咱们在本章会讲到的功能Cargo 甚至能完成更多,因此对于 Cargo 全部特性的完整阐释,请参阅 [他的文档](https://doc.rust-lang.org/cargo/)。 相比咱们在本章会讲到的功能Cargo 甚至能完成更多,因此对于 Cargo 全部特性的完整阐释,请参阅 [他的文档](https://doc.rust-lang.org/cargo/)。
End

View File

@ -21,3 +21,8 @@
此外,咱们还将讨论 *内部可变性interior mutability* 模式,在这种模式下,不可变的类型会暴露出一个用于改变内部值的 API。我们还将讨论引用循环他们如何泄漏内存以及如何防止他们。 此外,咱们还将讨论 *内部可变性interior mutability* 模式,在这种模式下,不可变的类型会暴露出一个用于改变内部值的 API。我们还将讨论引用循环他们如何泄漏内存以及如何防止他们。
下面就来切入正题吧! 下面就来切入正题吧!
End

View File

@ -19,3 +19,8 @@
- *状态共用shared-state* 方面的并发,其中多个线程均对某个数据加以访问; - *状态共用shared-state* 方面的并发,其中多个线程均对某个数据加以访问;
- `Sync``Send` 特质,他们俩把 Rust 并发方面的保证,扩展到 Rust 使用者所定义的类型,以及由标准库所提供的那些类型。 - `Sync``Send` 特质,他们俩把 Rust 并发方面的保证,扩展到 Rust 使用者所定义的类型,以及由标准库所提供的那些类型。
End

View File

@ -3,3 +3,8 @@
**Object Oriented Programming Features of Rust** **Object Oriented Programming Features of Rust**
面向对象编程方法object-oriented programming, OOP, 是建模程序的一种方法。对象是在 20 世纪 60 年代,在编程语言 Simula 中所引入的一个程序化概念。正是那些对象,影响了 Alan Kay 的编程架构,其中对象会相互传递消息。为描述这种架构,他在 1967 年创造了面向对象编程这个术语。有许多互相竞争的定义,都描述了 OOP 是什么而根据其中一些定义Rust 属于面向对象的但根据另一些Rust 则不属于面向对象的。在本章中,咱们将探讨通常被看作是面向对象的一些特征,以及这些特征怎样被转译为 Rust 的习惯说法。随后咱们将给出在 Rust 怎样实现面向对象的设计模式,并讨论在这样做,与相反采用 Rust 的一些长处来实现解决方案,之间的权衡取舍。 面向对象编程方法object-oriented programming, OOP, 是建模程序的一种方法。对象是在 20 世纪 60 年代,在编程语言 Simula 中所引入的一个程序化概念。正是那些对象,影响了 Alan Kay 的编程架构,其中对象会相互传递消息。为描述这种架构,他在 1967 年创造了面向对象编程这个术语。有许多互相竞争的定义,都描述了 OOP 是什么而根据其中一些定义Rust 属于面向对象的但根据另一些Rust 则不属于面向对象的。在本章中,咱们将探讨通常被看作是面向对象的一些特征,以及这些特征怎样被转译为 Rust 的习惯说法。随后咱们将给出在 Rust 怎样实现面向对象的设计模式,并讨论在这样做,与相反采用 Rust 的一些长处来实现解决方案,之间的权衡取舍。
End

View File

@ -21,3 +21,8 @@
要运用某个模式,咱们就要将其与某个值比较。在该模式与那个值匹配时,咱们在咱们的代码中,使用这个值的那些部分。回顾第 6 章中用到模式的那些 `match` 表达式,比如那个硬币分类机器示例。在值满足模式形状时,咱们就可以使用那些命名的代码片段。而在不满足时,与该模式关系的代码就不会运行。 要运用某个模式,咱们就要将其与某个值比较。在该模式与那个值匹配时,咱们在咱们的代码中,使用这个值的那些部分。回顾第 6 章中用到模式的那些 `match` 表达式,比如那个硬币分类机器示例。在值满足模式形状时,咱们就可以使用那些命名的代码片段。而在不满足时,与该模式关系的代码就不会运行。
本章时与模式相关全部内容的一个参考。咱们将涵盖运用模式的那些有效位置、可证伪与不可证伪模式的区别the difference between refutable and irrefutable patterns以及可能见到的那些不同类别的模式语法。在本章最后咱们将获悉如何运用模式来清晰地表达许多概念。 本章时与模式相关全部内容的一个参考。咱们将涵盖运用模式的那些有效位置、可证伪与不可证伪模式的区别the difference between refutable and irrefutable patterns以及可能见到的那些不同类别的模式语法。在本章最后咱们将获悉如何运用模式来清晰地表达许多概念。
End

View File

@ -18,3 +18,8 @@
本章是给每个人应该了解的,一整套 Rust 特性!咱们就开始吧! 本章是给每个人应该了解的,一整套 Rust 特性!咱们就开始吧!
End

View File

@ -26,3 +26,8 @@
在咱们开始动手前,咱们应注意到一个情况:咱们将运用的方法,将不会是在 Rust 下构建 web 服务器的最佳方法。在 [crates.io](https://crates.io/) 上,一些社区成员已经发布了数个,适合用于生产环境,提供了更完整功能的 web 服务器,以及咱们将要构建的线程池实现的代码箱。但是,本章中咱们的意图,是要帮助咱们学习掌握,而非走那样的捷径。由于 Rust 是门系统编程语言,因此咱们可以选择咱们打算着手的抽象层次,并可以触及到相比其他语言中,可行的或可操作的更低级别。因此咱们将亲自编写这个基本的 HTTP 服务器与线程池,如此咱们便可以学习这些代码箱之后的,今后可能会用到的一些一般概念与技巧。 在咱们开始动手前,咱们应注意到一个情况:咱们将运用的方法,将不会是在 Rust 下构建 web 服务器的最佳方法。在 [crates.io](https://crates.io/) 上,一些社区成员已经发布了数个,适合用于生产环境,提供了更完整功能的 web 服务器,以及咱们将要构建的线程池实现的代码箱。但是,本章中咱们的意图,是要帮助咱们学习掌握,而非走那样的捷径。由于 Rust 是门系统编程语言,因此咱们可以选择咱们打算着手的抽象层次,并可以触及到相比其他语言中,可行的或可操作的更低级别。因此咱们将亲自编写这个基本的 HTTP 服务器与线程池,如此咱们便可以学习这些代码箱之后的,今后可能会用到的一些一般概念与技巧。
End

View File

@ -1,3 +1,8 @@
# 附录 # 附录
以下小节包含了在咱们的 Rust 路途中,会发现有用的一些参考资料。 以下小节包含了在咱们的 Rust 路途中,会发现有用的一些参考资料。
End

View File

@ -132,3 +132,8 @@ fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
接下来,咱们就要看看宏了! 接下来,咱们就要看看宏了!
End

View File

@ -475,3 +475,8 @@ fn main() {
即使不牵涉到特质,这种新型模式也是有用的。接下来就要转换一下视角,而看看与 Rust 的类型系统交互的一些高级方式。 即使不牵涉到特质,这种新型模式也是有用的。接下来就要转换一下视角,而看看与 Rust 的类型系统交互的一些高级方式。
End

View File

@ -248,3 +248,8 @@ fn generic<T: ?Sized>(t: &T) {
还要注意咱们已将那个参数 `t` 的类型,从 `T` 更换为了 `&T`。由于这个类型可能不是 `Sized`,因此咱们就需要在某种指针之后使用他。在这种情况下,咱们选择了一个引用。 还要注意咱们已将那个参数 `t` 的类型,从 `T` 更换为了 `&T`。由于这个类型可能不是 `Sized`,因此咱们就需要在某种指针之后使用他。在这种情况下,咱们选择了一个引用。
接下来,咱们将谈谈函数与闭包! 接下来,咱们将谈谈函数与闭包!
End

View File

@ -364,3 +364,8 @@ pub fn sql(input: TokenStream) -> TokenStream {
接下来,咱们将把这正本书中曾讨论过的所有内容,投入到实践中,而完成另一个项目! 接下来,咱们将把这正本书中曾讨论过的所有内容,投入到实践中,而完成另一个项目!
End

View File

@ -449,3 +449,8 @@ fn main() {}
运用 `unsafe` 来采取上述五种做法(超能力)没有什么过错,或者不受欢迎。但由于编译器无法助力于保持内存安全,因此要让 `unsafe` 代码正确就更为棘手一些。在有使用 `unsafe` 代码的某种理由时,就可以这样做,而在问题出现时,显式的 `unsafe` 注解,就会令到排查问题原因更为容易。 运用 `unsafe` 来采取上述五种做法(超能力)没有什么过错,或者不受欢迎。但由于编译器无法助力于保持内存安全,因此要让 `unsafe` 代码正确就更为棘手一些。在有使用 `unsafe` 代码的某种理由时,就可以这样做,而在问题出现时,显式的 `unsafe` 注解,就会令到排查问题原因更为容易。
End

View File

@ -114,3 +114,8 @@
`Default::default` 函数,通常是与第 5 章中 [“使用结构体更新语法从其他实例创建出实例”](Ch05_Using_Structs_to_Structure_Related_Data.md#使用结构体更新语法从其他实例创建出实例) 小节里曾讨论过的结构体更新语法结合使用的。咱们可以定制结构体的几个字段,并在随后通过使用 `..Default::default()`,为其余字段设置并使用默认值。 `Default::default` 函数,通常是与第 5 章中 [“使用结构体更新语法从其他实例创建出实例”](Ch05_Using_Structs_to_Structure_Related_Data.md#使用结构体更新语法从其他实例创建出实例) 小节里曾讨论过的结构体更新语法结合使用的。咱们可以定制结构体的几个字段,并在随后通过使用 `..Default::default()`,为其余字段设置并使用默认值。
`Option<T>` 实例上使用 `unwrap_or_default` 方法时,便是需要 `Default` 特质的一个示例。当那个 `Option<T>``None` 时,方法 `unwrap_or_default` 就将返回存储在 `Option<T>` 中,那个类型 `T``Default::default` 结果。 `Option<T>` 实例上使用 `unwrap_or_default` 方法时,便是需要 `Default` 特质的一个示例。当那个 `Option<T>``None` 时,方法 `unwrap_or_default` 就将返回存储在 `Option<T>` 中,那个类型 `T``Default::default` 结果。
End

View File

@ -160,3 +160,8 @@ fn main() {
为帮助 IDE 集成Rust 社区建议使用 [`rust-analyzer`](https://rust-analyzer.github.io/)。此工具是一套以编译器为中心,操 [语言服务器协议Language Server Protocol](http://langserver.org/) 的实用工具;而所谓语言服务器协议,则是用于各种 IDEs 和编程语言,二者相互之间通信的一种规格。有多种不同客户端可使用 `rust-analyzer`,比如 [Visual Studio Code 的 Rust 分析器插件](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)。 为帮助 IDE 集成Rust 社区建议使用 [`rust-analyzer`](https://rust-analyzer.github.io/)。此工具是一套以编译器为中心,操 [语言服务器协议Language Server Protocol](http://langserver.org/) 的实用工具;而所谓语言服务器协议,则是用于各种 IDEs 和编程语言,二者相互之间通信的一种规格。有多种不同客户端可使用 `rust-analyzer`,比如 [Visual Studio Code 的 Rust 分析器插件](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)。
请访问 `rust-analyzer` 项目 [主页](https://rust-analyzer.github.io/),了解其安全说明,随后在咱们的特定 IDE 中安装该语言的服务器支持。咱们的 IDE 就能获得诸如自动补全、跳至定义及行内报错等能力。 请访问 `rust-analyzer` 项目 [主页](https://rust-analyzer.github.io/),了解其安全说明,随后在咱们的特定 IDE 中安装该语言的服务器支持。咱们的 IDE 就能获得诸如自动补全、跳至定义及行内报错等能力。
End

View File

@ -25,3 +25,8 @@ Rust 语言及编译器有着六周的发布周期,意味着用户会得到源
要明确的是:绝大多数特性,在所有版本上都将可用。使用任何 Rust 版本的开发者,都将在新的稳定发布构造出来时,发现一些改进。但是,在一些情况下,主要是在新曾了关键字时,一些新特性就会只在稍后版本中可用了。若咱们打算利用上这些新特性,咱们将需要切换版本。 要明确的是:绝大多数特性,在所有版本上都将可用。使用任何 Rust 版本的开发者,都将在新的稳定发布构造出来时,发现一些改进。但是,在一些情况下,主要是在新曾了关键字时,一些新特性就会只在稍后版本中可用了。若咱们打算利用上这些新特性,咱们将需要切换版本。
有关更多细节,[版本指南Edition Guide](https://doc.rust-lang.org/stable/edition-guide/) 是本列举了不同版本间差异,并解释了怎样通过 `cargo fix`,而自动将咱们的代码更新到新版的一本完整的书。 有关更多细节,[版本指南Edition Guide](https://doc.rust-lang.org/stable/edition-guide/) 是本列举了不同版本间差异,并解释了怎样通过 `cargo fix`,而自动将咱们的代码更新到新版的一本完整的书。
End

View File

@ -116,3 +116,8 @@ fn main() {
此代码将不带任何错误地编译。请注意那个函数的定义中,与 `main` 中该函数被调用处其名字上的 `r#` 前缀。 此代码将不带任何错误地编译。请注意那个函数的定义中,与 `main` 中该函数被调用处其名字上的 `r#` 前缀。
原始标识符实现了将任何咱们所选的词语用作标识符,即使那个词语碰巧是个保留的关键字。这给到咱们更自由地选择标识符名字,以及实现与一些以其中这些词语不属于关键字的语言,所编写的程序集成。此外,原始标识符实现了,对那些以不同于咱们代码箱 Rust 版本编写库加以运用。比如,在 2015 版中 `try` 就不是个关键字,但在 2018 版本中却是。若咱们依赖于一个使用 2015 版本编写的库,而该库有一个 `try` 函数,那么咱们就将需要在这种情况下,使用原始标识符 `r#try`,来从咱们的 2018 版本的代码,调用那个函数。请参阅 [附录 E](#appendix-e) 了解更多有关版本的信息。 原始标识符实现了将任何咱们所选的词语用作标识符,即使那个词语碰巧是个保留的关键字。这给到咱们更自由地选择标识符名字,以及实现与一些以其中这些词语不属于关键字的语言,所编写的程序集成。此外,原始标识符实现了,对那些以不同于咱们代码箱 Rust 版本编写库加以运用。比如,在 2015 版中 `try` 就不是个关键字,但在 2018 版本中却是。若咱们依赖于一个使用 2015 版本编写的库,而该库有一个 `try` 函数,那么咱们就将需要在这种情况下,使用原始标识符 `r#try`,来从咱们的 2018 版本的代码,调用那个函数。请参阅 [附录 E](#appendix-e) 了解更多有关版本的信息。
End

View File

@ -41,3 +41,8 @@ $ rustup component add llvm-tools-preview
``` ```
End

View File

@ -200,3 +200,8 @@
| `[type; len]` | 包含着 `len``type` 的实例数组的字面值 | | `[type; len]` | 包含着 `len``type` 的实例数组的字面值 |
| `expr[expr]` | 对集合进行索引collection indexing。是可过载的 `(Index, IndexMut)`overloadable `(Index, IndexMut)` | | `expr[expr]` | 对集合进行索引collection indexing。是可过载的 `(Index, IndexMut)`overloadable `(Index, IndexMut)` |
| `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]` | 用到了 `Range`、`RangeFrom`、`RangeTo` 或 `RangeFull` 作为 “索引”的带有集合切片集合索引collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, or `RangeFull` as the "index" | | `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]` | 用到了 `Range`、`RangeFrom`、`RangeTo` 或 `RangeFull` 作为 “索引”的带有集合切片集合索引collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, or `RangeFull` as the "index" |
End

View File

@ -139,3 +139,8 @@ $ rustup override set nightly
若该特性被接受了,就会在 Rust 代码仓库上开出一个 issue同时某个人就可以实现他。将其实现得非常棒的那个人可能不是最早提议这项特性的那人在实现准备好时其就会落地于 `master` 分支的特性门a feature gate之后如同咱们曾在 [“不稳定特性”](#不稳定特性) 小节中曾讨论过的那样。 若该特性被接受了,就会在 Rust 代码仓库上开出一个 issue同时某个人就可以实现他。将其实现得非常棒的那个人可能不是最早提议这项特性的那人在实现准备好时其就会落地于 `master` 分支的特性门a feature gate之后如同咱们曾在 [“不稳定特性”](#不稳定特性) 小节中曾讨论过的那样。
过了一段时间后,一旦那些用到每日发布的 Rust 开发者们,能够试用这项新特性,那么 Rust 团队成员将讨论这项特性,怎样将其编制到每日发布上,并决定其是否有那个被构造到稳定发布 Rust。而若决定是继续推进那么特性门就会被移除同时这项特性就被认为是稳定的了他就会搭上列车进到一个新的稳定发布 Rust 中。 过了一段时间后,一旦那些用到每日发布的 Rust 开发者们,能够试用这项新特性,那么 Rust 团队成员将讨论这项特性,怎样将其编制到每日发布上,并决定其是否有那个被构造到稳定发布 Rust。而若决定是继续推进那么特性门就会被移除同时这项特性就被认为是稳定的了他就会搭上列车进到一个新的稳定发布 Rust 中。
End

View File

@ -162,3 +162,8 @@ Input lifetimes函数或方法上的生命周期
- 输出生命周期 - 输出生命周期
Output lifetimes, 返回值上的生命周期 Output lifetimes, 返回值上的生命周期
End

View File

@ -2,3 +2,8 @@
<> <>
End

View File

@ -377,3 +377,8 @@ running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
``` ```
End

View File

@ -790,3 +790,8 @@ mod tests {
既然咱们已经了解了编写测试的几种方式,那么就来看一下,在运行这些编写的测试时会发生什么,并探索一下可与 `cargo test` 一起使用的不同选项。 既然咱们已经了解了编写测试的几种方式,那么就来看一下,在运行这些编写的测试时会发生什么,并探索一下可与 `cargo test` 一起使用的不同选项。
End

View File

@ -271,3 +271,8 @@ fn it_adds_two() {
Rust 的这些测试特性,提供到一种指明代码应如何生效,从而确保即使在进行了修改时,其仍继续如预期那样工作的方式。单元测试对库的各个部分进行单独检查,而可对一些私有实现细节进行测试。集成测试则对库的多个部分一起正确运作进行检查,同时他们会使用库的公开 API以与外部代码使用库的同样方式对代码进行测试。即使 Rust 的类型系统与所有权规则有助于防止某些种类的代码错误,对于消除与所编写代码预期表现方式有关的逻辑错误,测试仍是必不可少的。 Rust 的这些测试特性,提供到一种指明代码应如何生效,从而确保即使在进行了修改时,其仍继续如预期那样工作的方式。单元测试对库的各个部分进行单独检查,而可对一些私有实现细节进行测试。集成测试则对库的多个部分一起正确运作进行检查,同时他们会使用库的公开 API以与外部代码使用库的同样方式对代码进行测试。即使 Rust 的类型系统与所有权规则有助于防止某些种类的代码错误,对于消除与所编写代码预期表现方式有关的逻辑错误,测试仍是必不可少的。
下面就来将本章以及前面那些章中所掌握的知识结合起来,在一个项目上练手一下了! 下面就来将本章以及前面那些章中所掌握的知识结合起来,在一个项目上练手一下了!
End

View File

@ -256,3 +256,8 @@ error: could not compile `hashmap_demo` due to 2 previous errors
标准库 API 文档对矢量、字符串及哈希图有着的、对这些练习将有帮助的方法都有说明! 标准库 API 文档对矢量、字符串及哈希图有着的、对这些练习将有帮助的方法都有说明!
接下来就要进入到一些其中某些操作可能失败的程序,那么现在就是讨论错误处理的最佳时机。下一章就要来完成对错误处理的讨论了! 接下来就要进入到一些其中某些操作可能失败的程序,那么现在就是讨论错误处理的最佳时机。下一章就要来完成对错误处理的讨论了!
End

View File

@ -356,3 +356,8 @@ thread 'main' panicked at 'byte index 1 is not a char boundary; it is inside 'З
总的来说字符串是复杂的。不同编程语言在以何种程度将这种复杂度呈现给编程者上做出了不同的选择。Rust 选择了将正确处理 `String` 数据,作为所有 Rust 程序的默认行为,这就意味着 Rust 程序员就必须在处理 UTF-9 数据时,要提前投入更多思考。这种权衡暴露了相较于其他编程语言,更多的字符串复杂度,但这防止了在软件开发生命周期后期,将涉及到的非 ASCII 字符的错误处理。 总的来说字符串是复杂的。不同编程语言在以何种程度将这种复杂度呈现给编程者上做出了不同的选择。Rust 选择了将正确处理 `String` 数据,作为所有 Rust 程序的默认行为,这就意味着 Rust 程序员就必须在处理 UTF-9 数据时,要提前投入更多思考。这种权衡暴露了相较于其他编程语言,更多的字符串复杂度,但这防止了在软件开发生命周期后期,将涉及到的非 ASCII 字符的错误处理。
接下来就要换到,有点复杂的东西:哈希图! 接下来就要换到,有点复杂的东西:哈希图!
End

View File

@ -214,3 +214,8 @@ Rust 需要在编译时了解那个矢量中会有些什么类型,这样他就
下面就移步到下一种集合类型:`String` 吧! 下面就移步到下一种集合类型:`String` 吧!
End

View File

@ -48,3 +48,8 @@
Rust 标准库提供了用于消息传递的信道,以及诸如 `Mutex<T>``Arc<T>` 等安全用于并发情景中的一些灵巧指针类型。类型系统与借用检查器,会确保应用了这些方案的代码,不会以数据竞争或无效引用结束。一旦让代码编译了,咱们就可以放下心来,代码将愉快地运行于多线程之上,而不会有在其他语言中常见的那些难于追踪的问题。并发编程自此不再是令人害怕的概念:去吧,让你的程序并发起来,无所畏惧! Rust 标准库提供了用于消息传递的信道,以及诸如 `Mutex<T>``Arc<T>` 等安全用于并发情景中的一些灵巧指针类型。类型系统与借用检查器,会确保应用了这些方案的代码,不会以数据竞争或无效引用结束。一旦让代码编译了,咱们就可以放下心来,代码将愉快地运行于多线程之上,而不会有在其他语言中常见的那些难于追踪的问题。并发编程自此不再是令人害怕的概念:去吧,让你的程序并发起来,无所畏惧!
接下来,咱们将讲到,随着咱们的 Rust 程序变得大了起来,建模问题与架构出方案的一些管用做法。此外,咱们将讨论 Rust 的一些习惯说法,这些说法可能与面向对象编程中所熟悉的有关。 接下来,咱们将讲到,随着咱们的 Rust 程序变得大了起来,建模问题与架构出方案的一些管用做法。此外,咱们将讨论 Rust 的一些习惯说法,这些说法可能与面向对象编程中所熟悉的有关。
End

View File

@ -271,3 +271,8 @@ fn main() {
根据咱们所在系统的不同,也可能会看到另外顺序的这些值。这种消息每次出现顺序的不一致,正是令到并发有趣而又有难度的地方。而若带上 `thread::sleep` 加以实验,即在两个不同线程中给到不同睡眠值,这时的每次运行,将更具不确定性,而每次运行都造成不同输出。 根据咱们所在系统的不同,也可能会看到另外顺序的这些值。这种消息每次出现顺序的不一致,正是令到并发有趣而又有难度的地方。而若带上 `thread::sleep` 加以实验,即在两个不同线程中给到不同睡眠值,这时的每次运行,将更具不确定性,而每次运行都造成不同输出。
既然咱们已经看到了信道的工作原理,那么接下来就要看看一种方式迥异的并发了。 既然咱们已经看到了信道的工作原理,那么接下来就要看看一种方式迥异的并发了。
End

View File

@ -266,3 +266,8 @@ fn main() {
另一个需要注意的细节,便是在咱们使用 `Mutex<T>`Rust 无法保护咱们免于全部类别的逻辑错误。回顾在第 15 章中,`Rc<T>` 运用就伴随着创建出循环引用风险,其中两个 `Rc<T>` 值相互指向,导致内存泄漏。与此类似,`Mutex<T>` 则附带着创建出 *死锁deadlocks* 的风险。在某个操作需要锁住两项资源,同时两个线程分别均已请求获取两把锁中的一把时,就造成他们一直等待着对方释放各自所需的锁。若对死锁方面感兴趣,那么请尝试创建出有着死锁的一个 Rust 程序;随后就要研究任何一门语言中,互斥量的死锁消除策略,并试试在 Rust 中实现这些策略。`Mutex<T>` 和 `MutexGuard` 的标准库 API 文档,就提供了一些有用信息。 另一个需要注意的细节,便是在咱们使用 `Mutex<T>`Rust 无法保护咱们免于全部类别的逻辑错误。回顾在第 15 章中,`Rc<T>` 运用就伴随着创建出循环引用风险,其中两个 `Rc<T>` 值相互指向,导致内存泄漏。与此类似,`Mutex<T>` 则附带着创建出 *死锁deadlocks* 的风险。在某个操作需要锁住两项资源,同时两个线程分别均已请求获取两把锁中的一把时,就造成他们一直等待着对方释放各自所需的锁。若对死锁方面感兴趣,那么请尝试创建出有着死锁的一个 Rust 程序;随后就要研究任何一门语言中,互斥量的死锁消除策略,并试试在 Rust 中实现这些策略。`Mutex<T>` 和 `MutexGuard` 的标准库 API 文档,就提供了一些有用信息。
咱们将通过讲解 `Send``Sync` 两个特质,以及怎样与一些定制类型来运用他们来完结本章。 咱们将通过讲解 `Send``Sync` 两个特质,以及怎样与一些定制类型来运用他们来完结本章。
End

View File

@ -320,3 +320,8 @@ error: could not compile `concur_demo` due to previous error
Rust 的所有权规则,再次挽救了咱们!由于 Rust 一直以来的保守,以及只为那个线程借用了 `v`,就意味着主线程理论上可以令到生成线程的引用失效,而得到了清单 16-3 中代码的报错。通过告知 Rust 将 `v` 的所有权迁移到生成线程,咱们就向 Rust 保证了主线程不会再使用 `v`。而若咱们以同样方式修改清单 16-4那么随后在咱们于主线程中尝试使用 `v` 时,就破坏了那些所有权规则。这个 `move` 关键字,覆盖了 Rust 借用方面的保守做法;但他并无让咱们破坏所有权规则。 Rust 的所有权规则,再次挽救了咱们!由于 Rust 一直以来的保守,以及只为那个线程借用了 `v`,就意味着主线程理论上可以令到生成线程的引用失效,而得到了清单 16-3 中代码的报错。通过告知 Rust 将 `v` 的所有权迁移到生成线程,咱们就向 Rust 保证了主线程不会再使用 `v`。而若咱们以同样方式修改清单 16-4那么随后在咱们于主线程中尝试使用 `v` 时,就破坏了那些所有权规则。这个 `move` 关键字,覆盖了 Rust 借用方面的保守做法;但他并无让咱们破坏所有权规则。
有了线程及线程 API 方面的基本认识,接下来就有看看用线程可以 *做do* 些什么。 有了线程及线程 API 方面的基本认识,接下来就有看看用线程可以 *做do* 些什么。
End

View File

@ -74,3 +74,8 @@ $ cargo install ripgrep
``` ```
输出的倒数第二行显示出已安装二进制程序的位置与名字,在这个示例中名字便是 `rg`。正如前面提到的,只要安装目录是在 `$PATH` 中,随后咱们就可以运行 `rg --help`,并启动一个用于检索文件的更快、更具 Rust 风格的工具了! 输出的倒数第二行显示出已安装二进制程序的位置与名字,在这个示例中名字便是 `rg`。正如前面提到的,只要安装目录是在 `$PATH` 中,随后咱们就可以运行 `rg --help`,并启动一个用于检索文件的更快、更具 Rust 风格的工具了!
End

View File

@ -8,3 +8,8 @@ Cargo 被设计为在无需修改 Cargo 下,咱们就可以使用新的子命
# 本章小结 # 本章小结
运用 Cargo 与 [crates.io](https://crates.io) 分享代码,是令到 Rust 生态对于许多不同任务都有用的一个方面。Rust 的标准库是小型且稳定的,但在不同于语言本身的时间线上,代码箱则易于共享、运用以及改进。请不要羞于在 [crates.io](https://crates.io) 上分享对自己有用的代码;那些代码或许对其他人也同样有用! 运用 Cargo 与 [crates.io](https://crates.io) 分享代码,是令到 Rust 生态对于许多不同任务都有用的一个方面。Rust 的标准库是小型且稳定的,但在不同于语言本身的时间线上,代码箱则易于共享、运用以及改进。请不要羞于在 [crates.io](https://crates.io) 上分享对自己有用的代码;那些代码或许对其他人也同样有用!
End

View File

@ -443,3 +443,8 @@ $ cargo yank --vers 0.1.0 --undo
``` ```
抽出版本,*不会* 删除任何代码。比如,其无法删除那些不小心上传的机密信息。若发生了机密信息被上传的情况,咱们必须立即重置这些机密信息。 抽出版本,*不会* 删除任何代码。比如,其无法删除那些不小心上传的机密信息。若发生了机密信息被上传的情况,咱们必须立即重置这些机密信息。
End

View File

@ -44,3 +44,8 @@ opt-level = 1
此代码会覆盖默认设置 `0`。现在当咱们运行 `cargo build`Cargo 将使用 `dev` 配置文件的默认设置,加上咱们对 `opt-level` 的定制。由于咱们把 `opt-level` 设置为了 `1`Cargo 将应用相比于默认设置更多,但不如发布构建那样多的优化。 此代码会覆盖默认设置 `0`。现在当咱们运行 `cargo build`Cargo 将使用 `dev` 配置文件的默认设置,加上咱们对 `opt-level` 的定制。由于咱们把 `opt-level` 设置为了 `1`Cargo 将应用相比于默认设置更多,但不如发布构建那样多的优化。
对于各个配置文件的完整配置项清单与默认设置,请参阅 [Cargo 文档](https://doc.rust-lang.org/cargo/reference/profiles.html)。 对于各个配置文件的完整配置项清单与默认设置,请参阅 [Cargo 文档](https://doc.rust-lang.org/cargo/reference/profiles.html)。
End

View File

@ -302,3 +302,8 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; fini
作为附加练习,请以与 `add_one` 代码箱类似方式,把 `add_two` 添加到这个工作区! 作为附加练习,请以与 `add_one` 代码箱类似方式,把 `add_two` 添加到这个工作区!
当咱们的项目日渐增长时,请考虑使用工作区:相比于一大块代码,要搞清楚较小的、单独的组件就更容易一些。再者,当代码箱经常同时被修改时,把这些代码箱保持在工作区中,就能令到他们之间的协作更容易。 当咱们的项目日渐增长时,请考虑使用工作区:相比于一大块代码,要搞清楚较小的、单独的组件就更容易一些。再者,当代码箱经常同时被修改时,把这些代码箱保持在工作区中,就能令到他们之间的协作更容易。
End

View File

@ -295,3 +295,8 @@ error: could not compile `option_demo` (bin "option_demo") due to previous error
那么,当咱们有着某个 `Option<T>` 类型的值时,该怎样从 `Some` 变种中获取到那个 `T` 值,以便使用该值呢?`Option<T>` 这个枚举,有着大量在不同场景下,都有用的方法;咱们可以在 [其文档](https://doc.rust-lang.org/std/option/enum.Option.html) 中,查看这些方法。熟悉 `Option<T>` 的方法,将对咱们的 Rust 之旅大有裨益。 那么,当咱们有着某个 `Option<T>` 类型的值时,该怎样从 `Some` 变种中获取到那个 `T` 值,以便使用该值呢?`Option<T>` 这个枚举,有着大量在不同场景下,都有用的方法;咱们可以在 [其文档](https://doc.rust-lang.org/std/option/enum.Option.html) 中,查看这些方法。熟悉 `Option<T>` 的方法,将对咱们的 Rust 之旅大有裨益。
一般来说,为了使用某个 `Option<T>` 值,咱们需要编写处理每个变种的代码。咱们会想要一些,仅在咱们有个 `Some(T)` 值时才会运行的代码,而这些代码,就可以使用内部的 `T` 值;咱们会想要另一些,只有在咱们有个 `None` 值时才会运行的代码,而这些代码就没有可用的 `T` 值。与枚举一起使用的 `match` 表达式,便是一种正好完成这个目的的控制流结构:他会根据枚举有着哪一个变种,而运行不同的代码,而这些代码,就可以使用匹配值内部的数据。 一般来说,为了使用某个 `Option<T>` 值,咱们需要编写处理每个变种的代码。咱们会想要一些,仅在咱们有个 `Some(T)` 值时才会运行的代码,而这些代码,就可以使用内部的 `T` 值;咱们会想要另一些,只有在咱们有个 `None` 值时才会运行的代码,而这些代码就没有可用的 `T` 值。与枚举一起使用的 `match` 表达式,便是一种正好完成这个目的的控制流结构:他会根据枚举有着哪一个变种,而运行不同的代码,而这些代码,就可以使用匹配值内部的数据。
End

View File

@ -80,3 +80,8 @@ if let Coin::Quarter(state) = coin {
咱们的 Rust 程序现在可以使用结构体和枚举,来表达咱们领域中的概念了。在咱们的 API 中创建一些自定义类型,确保了类型安全:编译器将确保咱们的函数,只获取到每个他们所期望类型的值。 咱们的 Rust 程序现在可以使用结构体和枚举,来表达咱们领域中的概念了。在咱们的 API 中创建一些自定义类型,确保了类型安全:编译器将确保咱们的函数,只获取到每个他们所期望类型的值。
为了向咱们的用户,提供组织良好、简单易用的 API并且只暴露出咱们用户所需的内容我们现在来看看 Rust 的模组。 为了向咱们的用户,提供组织良好、简单易用的 API并且只暴露出咱们用户所需的内容我们现在来看看 Rust 的模组。
End

View File

@ -287,3 +287,8 @@ fn remove_fancy_hat() {}
在这里,我们显式地告诉 Rust我们不会使用任何与先前支臂中模式不匹配的其他值且在这种情况下我们不打算运行任何代码。 在这里,我们显式地告诉 Rust我们不会使用任何与先前支臂中模式不匹配的其他值且在这种情况下我们不打算运行任何代码。
我们将在 [第 18 章](../Ch18_Patterns_and_Matching.md) 中,结束更多有关模式与匹配的内容。现在,我们将继续讨论 `if let` 这种语法,其在 `match` 表达式显得有些冗长的情况下,非常有用。 我们将在 [第 18 章](../Ch18_Patterns_and_Matching.md) 中,结束更多有关模式与匹配的内容。现在,我们将继续讨论 `if let` 这种语法,其在 `match` 表达式显得有些冗长的情况下,非常有用。
End

View File

@ -104,3 +104,8 @@ note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose bac
在上面清单 9-2 里的输出中,回溯所指向到这里项目中行的第 6 行,就是导致问题的行:即 `src/main.rs` 的第 4 行。在不想要这个程序中止时,就应在首个提到了自己所编写文件的行,所指向的那个位置,开始排查。在之前的清单 9-1 中,那里有意编写了会中止的代码,而修正程序中止的办法,就是不要请求某个超出那个矢量索引范围的元素。而在今后代码中止时,就需要搞清楚代码是在对什么值进行何种操作,而导致了中止,以及代码应该怎么做。 在上面清单 9-2 里的输出中,回溯所指向到这里项目中行的第 6 行,就是导致问题的行:即 `src/main.rs` 的第 4 行。在不想要这个程序中止时,就应在首个提到了自己所编写文件的行,所指向的那个位置,开始排查。在之前的清单 9-1 中,那里有意编写了会中止的代码,而修正程序中止的办法,就是不要请求某个超出那个矢量索引范围的元素。而在今后代码中止时,就需要搞清楚代码是在对什么值进行何种操作,而导致了中止,以及代码应该怎么做。
在本章的 [要 `panic!` 或不要 `panic!`](#要-panic-还是不要-panic) 小节,将回到 `panic!` 这个话题,并讨论在何时要用 `panic!`,何时不应使用 `panic!` 来处理不同错误情形。接下来,就会看看怎样使用 `Result`,从错误中恢复过来。 在本章的 [要 `panic!` 或不要 `panic!`](#要-panic-还是不要-panic) 小节,将回到 `panic!` 这个话题,并讨论在何时要用 `panic!`,何时不应使用 `panic!` 来处理不同错误情形。接下来,就会看看怎样使用 `Result`,从错误中恢复过来。
End

View File

@ -134,3 +134,8 @@ impl Guess {
Rust 的那些错误处理特性,被设计用于帮助编写更为健壮的代码。`panic!` 这个宏,发出了程序处于其无法处理状态的信号,并让咱们告知进程停下来,而不是尝试以无效或不正确的一些值继续运行。而 `Result` 这个枚举则使用了 Rust 的类型系统来表示以代码可以从中恢复过来的某种方式的一些操作失败the `Result` enum uses Rust's type system to indicate that operations might fail in a way that your code could recover from。还可使用 `Result` 来告诉调用了咱们代码的代码,需要处理潜在的成功与失败情形。在一些适当情形下,运用 `panic!``Result` 就会令到咱们的代码在各种不可避免的问题面前,更加可靠。 Rust 的那些错误处理特性,被设计用于帮助编写更为健壮的代码。`panic!` 这个宏,发出了程序处于其无法处理状态的信号,并让咱们告知进程停下来,而不是尝试以无效或不正确的一些值继续运行。而 `Result` 这个枚举则使用了 Rust 的类型系统来表示以代码可以从中恢复过来的某种方式的一些操作失败the `Result` enum uses Rust's type system to indicate that operations might fail in a way that your code could recover from。还可使用 `Result` 来告诉调用了咱们代码的代码,需要处理潜在的成功与失败情形。在一些适当情形下,运用 `panic!``Result` 就会令到咱们的代码在各种不可避免的问题面前,更加可靠。
既然这里已经见识到标准库在 `Option``Result` 枚举上,运用到泛型的一些有用方式,那么接下来就要谈及泛型的原理,以及怎样在咱们的代码中运用泛型。 既然这里已经见识到标准库在 `Option``Result` 枚举上,运用到泛型的一些有用方式,那么接下来就要谈及泛型的原理,以及怎样在咱们的代码中运用泛型。
End

View File

@ -414,3 +414,8 @@ fn main() -> Result<(), Box<dyn Error>> {
End

View File

@ -451,3 +451,8 @@ impl Worker {
# 本章小结 # 本章小结
干得好!咱们已经读完了这整本书!要感谢咱们加入到这次 Rust 之旅中来。咱们现在已经准备好实现咱们自己的 Rust 项目,以及帮助其他人的项目了。请记住有那么一个由热衷于就咱们在 Rust 道路上,所遇到的任何挑战,而帮助咱们的其他 Rust 公民的热情社区。 干得好!咱们已经读完了这整本书!要感谢咱们加入到这次 Rust 之旅中来。咱们现在已经准备好实现咱们自己的 Rust 项目,以及帮助其他人的项目了。请记住有那么一个由热衷于就咱们在 Rust 道路上,所遇到的任何挑战,而帮助咱们的其他 Rust 公民的热情社区。
End

View File

@ -721,3 +721,8 @@ impl Worker {
这段代码将会编译及运行,但不会产生所需的线程行为:慢速请求仍将导致别的请求等待被处理。至于原因则有点微妙:由于锁的所有权是基于 `lock` 方法返回的 `LockResult<MutexGuard<T>>` 中,`MutexGuard<T>` 的生命周期,因此这个 `Mutex` 结构体没有公开的 `unlock` 方法。在编译时,借用检查器可于随后,就除非咱们拿着 `Mutex` 所守卫的某项资源的锁,否则无法访问该项资源这一规则强制加以检查。但是,若咱们没有注意到 `MutexGuard<T>` 的生命周期,那么这样的实现同样能导致锁相较预期被占用更长时间。 这段代码将会编译及运行,但不会产生所需的线程行为:慢速请求仍将导致别的请求等待被处理。至于原因则有点微妙:由于锁的所有权是基于 `lock` 方法返回的 `LockResult<MutexGuard<T>>` 中,`MutexGuard<T>` 的生命周期,因此这个 `Mutex` 结构体没有公开的 `unlock` 方法。在编译时,借用检查器可于随后,就除非咱们拿着 `Mutex` 所守卫的某项资源的锁,否则无法访问该项资源这一规则强制加以检查。但是,若咱们没有注意到 `MutexGuard<T>` 的生命周期,那么这样的实现同样能导致锁相较预期被占用更长时间。
由于在 `let` 之下,等号右侧的表达式中用到的任何临时值,都会在 `let` 语句结束时被立即丢弃,因此使用了 `let job = receiver.lock().unwrap().recv().unwrap();` 的清单 20-20 中代码是工作的。但是,`while let`(以及 `if let``match` 则是在相关代码块结束前,不会丢弃那些临时值。在清单 20-21 中,锁会在到 `job()` 的调用其将保持被持有,这意味着别的 `worker` 就没法收到作业。 由于在 `let` 之下,等号右侧的表达式中用到的任何临时值,都会在 `let` 语句结束时被立即丢弃,因此使用了 `let job = receiver.lock().unwrap().recv().unwrap();` 的清单 20-20 中代码是工作的。但是,`while let`(以及 `if let``match` 则是在相关代码块结束前,不会丢弃那些临时值。在清单 20-21 中,锁会在到 `job()` 的调用其将保持被持有,这意味着别的 `worker` 就没法收到作业。
End

View File

@ -455,3 +455,8 @@ fn handle_conn(mut stream: TcpStream) {
End

View File

@ -492,3 +492,8 @@ fn main() {
println! ("{:#?}\n{:#?}", list, sort_operations); println! ("{:#?}\n{:#?}", list, sort_operations);
} }
``` ```
End

View File

@ -223,3 +223,8 @@ pub fn search_insensitive<'a>(
下一个合乎逻辑的问题是,咱们应在自己的代码中选择哪种风格与为什么:清单 13-21 中原本的实现,或清单 13-22 中用到迭代器的版本。大多数 Rust 程序员喜欢使用迭代器风格。一开始他有点难掌握,但一旦咱们对各种迭代器适配器和他们的作用有了感觉,迭代器就会更容易理解。该代码没有拨弄循环的各个部分,与构建出新的矢量值,而是专注于循环的高级目标。这就把一些普通的代码抽象化了,所以更容易看到这段代码特有的概念,比如迭代器中每个元素必须通过的过滤条件。 下一个合乎逻辑的问题是,咱们应在自己的代码中选择哪种风格与为什么:清单 13-21 中原本的实现,或清单 13-22 中用到迭代器的版本。大多数 Rust 程序员喜欢使用迭代器风格。一开始他有点难掌握,但一旦咱们对各种迭代器适配器和他们的作用有了感觉,迭代器就会更容易理解。该代码没有拨弄循环的各个部分,与构建出新的矢量值,而是专注于循环的高级目标。这就把一些普通的代码抽象化了,所以更容易看到这段代码特有的概念,比如迭代器中每个元素必须通过的过滤条件。
但是,这两种实现方式真的等同吗?直观的假设可能是,更低级别的循环会更快。接下来咱们就会谈及性能问题。 但是,这两种实现方式真的等同吗?直观的假设可能是,更低级别的循环会更快。接下来咱们就会谈及性能问题。
End

View File

@ -244,3 +244,8 @@ mod tests {
闭包从环境中捕获到 `shoe_size` 参数,并将该值与每双鞋子的尺码比较,只保留特定尺码的鞋子。最后,调用 `collect` 方法,将调整出的迭代器返回的 `Shoe` 类型值,收集到一个矢量中,`shoes_in_size` 函数返回的,便是这个矢量值。 闭包从环境中捕获到 `shoe_size` 参数,并将该值与每双鞋子的尺码比较,只保留特定尺码的鞋子。最后,调用 `collect` 方法,将调整出的迭代器返回的 `Shoe` 类型值,收集到一个矢量中,`shoes_in_size` 函数返回的,便是这个矢量值。
测试表明,当咱们调用 `shoes_in_size` 时,只得到了与咱们指定的值相同大小的鞋子。 测试表明,当咱们调用 `shoes_in_size` 时,只得到了与咱们指定的值相同大小的鞋子。
End

View File

@ -48,3 +48,8 @@ for i in 12..buffer.len() {
闭包与迭代器,是 Rust 受函数式编程概念启发的两项特性。他们有助于 Rust 以底层性能清楚表达高级别概念的能力。闭包与迭代器的实现,不会影响到运行时性能。这正是 Rust 致力于提供零成本抽象目标的一部分。 闭包与迭代器,是 Rust 受函数式编程概念启发的两项特性。他们有助于 Rust 以底层性能清楚表达高级别概念的能力。闭包与迭代器的实现,不会影响到运行时性能。这正是 Rust 致力于提供零成本抽象目标的一部分。
现在我们已经改进了 I/O 项目的表达能力,让我们再来看看 `cargo` 的更多特性,这些特性将帮助我们与世界分享这个项目。 现在我们已经改进了 I/O 项目的表达能力,让我们再来看看 `cargo` 的更多特性,这些特性将帮助我们与世界分享这个项目。
End

View File

@ -372,3 +372,8 @@ fn main() {
End

View File

@ -572,3 +572,8 @@ where
在这一章中,咱们谈到了很多东西!现在咱们清楚了泛型参数、特质与特质边界,与泛型生命周期参数,那么就准备好编写在许多不同情况下工作,不带有重复的代码了。泛型参数实现了将代码应用于不同类型。特质与特质边界确保即使类型是通用的,他们仍将有着代码所需的行为。咱们了解了如何使用生命周期注解,来保证这种灵活代码不会有任何悬空引用。且所有分析,都发生在编译时,其不会影响到运行时性能! 在这一章中,咱们谈到了很多东西!现在咱们清楚了泛型参数、特质与特质边界,与泛型生命周期参数,那么就准备好编写在许多不同情况下工作,不带有重复的代码了。泛型参数实现了将代码应用于不同类型。特质与特质边界确保即使类型是通用的,他们仍将有着代码所需的行为。咱们了解了如何使用生命周期注解,来保证这种灵活代码不会有任何悬空引用。且所有分析,都发生在编译时,其不会影响到运行时性能!
不论相信与否,关于咱们在本章讨论的这些话题,要掌握的东西远不止这些:第 17 章会讨论特质对象trait objects其是运用特质的另一种方式。还有更多咱们只会在极复杂场景下才需要的涉及到更复杂场景的生命周期注解要了解那些生命周期注解咱们应阅读 [Rust 指南](https://doc.rust-lang.org/reference/index.html)。不过接下来,咱们将了解怎样编写 Rust 中的测试,从而就可以确保所咱们的代码,以其应有的方式工作。 不论相信与否,关于咱们在本章讨论的这些话题,要掌握的东西远不止这些:第 17 章会讨论特质对象trait objects其是运用特质的另一种方式。还有更多咱们只会在极复杂场景下才需要的涉及到更复杂场景的生命周期注解要了解那些生命周期注解咱们应阅读 [Rust 指南](https://doc.rust-lang.org/reference/index.html)。不过接下来,咱们将了解怎样编写 Rust 中的测试,从而就可以确保所咱们的代码,以其应有的方式工作。
End

View File

@ -392,3 +392,8 @@ let s = 3.to_string();
特质与特质边界这两个特性允许咱们编写出运用泛型参数来减少代码重复的代码并还向编译器指出了咱们希望该泛型有着特定行为。随后编译器就能使用特质边界信息来检查代码用到的全部具体类型是否提供到正确行为。在一般的动态类型语言dynamically typed languages若调用某个类型上尚未定义的方法咱们将在运行时收到报错。但 Rust 将这些错误移到了编译时,这样在代码还不能运行的时候,咱们就被强制要求修复这些问题。此外,由于已在编译时被检查过,因此咱们就不必编写检查运行时行为的代码。这样做在提升了性能的同时,不必放弃泛型灵活性。 特质与特质边界这两个特性允许咱们编写出运用泛型参数来减少代码重复的代码并还向编译器指出了咱们希望该泛型有着特定行为。随后编译器就能使用特质边界信息来检查代码用到的全部具体类型是否提供到正确行为。在一般的动态类型语言dynamically typed languages若调用某个类型上尚未定义的方法咱们将在运行时收到报错。但 Rust 将这些错误移到了编译时,这样在代码还不能运行的时候,咱们就被强制要求修复这些问题。此外,由于已在编译时被检查过,因此咱们就不必编写检查运行时行为的代码。这样做在提升了性能的同时,不必放弃泛型灵活性。
End

View File

@ -212,3 +212,8 @@ $ cargo build
这正是编写一个更大型程序,来习惯于读写 Rust 代码的大好时机。因此,在第 2 章中,我们将构建一个猜数游戏程序。如果咱们想从掌握那些常见编程概念,在 Rust 中的工作原理开始,那么请参阅第 3 章,然后返回第 2 章。 这正是编写一个更大型程序,来习惯于读写 Rust 代码的大好时机。因此,在第 2 章中,我们将构建一个猜数游戏程序。如果咱们想从掌握那些常见编程概念,在 Rust 中的工作原理开始,那么请参阅第 3 章,然后返回第 2 章。
End

View File

@ -162,3 +162,8 @@ $ ./main # 或在 Windows 上的 .\main.exe
如果咱们更熟悉 Ruby、Python 或 JavaScript 等某门动态语言则可能不习惯于将编译和运行某个程序作为单独的步骤。Rust 属于一门 *提前编译ahead-of-time compiled* 语言,这意味着,你能够编译某个程序,并把可执行文件交给其他人,而即使他们没有安装 Rust也可以运行这个可执行程序。而如果咱们给别人某个 `.rb`、`.py` 或 `.js` 文件,他们就需要分别安装 Ruby、Python 或 JavaScript 的某种实现。不过在这些语言中咱们只需要一条命令来编译并运行咱们的程序。在语言设计中一切都需要权衡利弊everything is a trade-off in language design。 如果咱们更熟悉 Ruby、Python 或 JavaScript 等某门动态语言则可能不习惯于将编译和运行某个程序作为单独的步骤。Rust 属于一门 *提前编译ahead-of-time compiled* 语言,这意味着,你能够编译某个程序,并把可执行文件交给其他人,而即使他们没有安装 Rust也可以运行这个可执行程序。而如果咱们给别人某个 `.rb`、`.py` 或 `.js` 文件,他们就需要分别安装 Ruby、Python 或 JavaScript 的某种实现。不过在这些语言中咱们只需要一条命令来编译并运行咱们的程序。在语言设计中一切都需要权衡利弊everything is a trade-off in language design。
对于简单程序,使用 `rustc` 编译就可以了,但随着项目的发展,咱们会希望管理所有选项,以及并方便共用咱们的代码。接下来,我们将介绍,将会帮助咱们编写真实世界 Rust 程序的 Cargo 工具。 对于简单程序,使用 `rustc` 编译就可以了,但随着项目的发展,咱们会希望管理所有选项,以及并方便共用咱们的代码。接下来,我们将介绍,将会帮助咱们编写真实世界 Rust 程序的 Cargo 工具。
End

View File

@ -204,3 +204,8 @@ $ rustup self uninstall
Rust 的安装,还包含了一份本地文档,以便咱们离线阅读。请运行 `rustup doc`,在咱们的浏览器中打开本地文档。 Rust 的安装,还包含了一份本地文档,以便咱们离线阅读。请运行 `rustup doc`,在咱们的浏览器中打开本地文档。
如果咱们不确定某个标准库提供的类型或函数的作用或使用方法请使用应用程序编程接口API文档来搞清楚 如果咱们不确定某个标准库提供的类型或函数的作用或使用方法请使用应用程序编程接口API文档来搞清楚
End

View File

@ -108,3 +108,8 @@ $ cargo run -- test sample.txt
``` ```
很好,这个程序工作了!所需参数的那些值正被保存到恰当的变量中。后面就要添加一些错误处理,来处理某些潜在的错误情形,诸如在用户未提供参数这样的情况;现在,这里将忽略那样的情况,而是会编写添加文件读取能力的代码。 很好,这个程序工作了!所需参数的那些值正被保存到恰当的变量中。后面就要添加一些错误处理,来处理某些潜在的错误情形,诸如在用户未提供参数这样的情况;现在,这里将忽略那样的情况,而是会编写添加文件读取能力的代码。
End

View File

@ -237,3 +237,8 @@ To an admiring bog!
有的程序,同时实现同一配置的命令行参数 *与* 环境变量。在这样的情形下,这些程序就会确定下其中之一有着较高优先级。好比你自己的另一代码练习中,就会尝试经由命令行参数,或同时经由环境变量,对是否区分大小写进行控制。就会在程序在一种设置下区分大小写,而另一种设置下不区分大小写时,对到底命令行参数优先,还是环境变量优先,加以确定。 有的程序,同时实现同一配置的命令行参数 *与* 环境变量。在这样的情形下,这些程序就会确定下其中之一有着较高优先级。好比你自己的另一代码练习中,就会尝试经由命令行参数,或同时经由环境变量,对是否区分大小写进行控制。就会在程序在一种设置下区分大小写,而另一种设置下不区分大小写时,对到底命令行参数优先,还是环境变量优先,加以确定。
这个 `std::env` 模组,包含了许多用于处理环境变量的其他有用特性:请查看其文档来看看有哪些可用特性。 这个 `std::env` 模组,包含了许多用于处理环境变量的其他有用特性:请查看其文档来看看有哪些可用特性。
End

View File

@ -68,3 +68,8 @@ To an admiring bog!
``` ```
很好!这代码就读取并于随后打印出了那个文件的内容。但这代码有着少数几个缺陷。此时的这个 `main` 函数,有着多重义务:一般来讲,在每个函数只负责一件事情时,那么他们就是些更为清晰明了,并更易于维护的函数了。另一问题则是这里没有尽可能地对错误进行处理。这个程序还很小,因此这些缺陷就不是什么大问题,不过随着程序变大,就会变得更加难于彻底修复这些缺陷。在开发某个程序时,由于重构数量较少的代码要容易得多,因此尽早开始重构,是一种良好实践。接下来就会干这件事 -- 重构。 很好!这代码就读取并于随后打印出了那个文件的内容。但这代码有着少数几个缺陷。此时的这个 `main` 函数,有着多重义务:一般来讲,在每个函数只负责一件事情时,那么他们就是些更为清晰明了,并更易于维护的函数了。另一问题则是这里没有尽可能地对错误进行处理。这个程序还很小,因此这些缺陷就不是什么大问题,不过随着程序变大,就会变得更加难于彻底修复这些缺陷。在开发某个程序时,由于重构数量较少的代码要容易得多,因此尽早开始重构,是一种良好实践。接下来就会干这件事 -- 重构。
End

View File

@ -499,3 +499,8 @@ fn main() {
咦!这可是干了很多活了,还好现在已经为将来的成功做好了准备。现在处理错误就容易多了,同时令到代码更具模块性。从现在开始,几乎咱们的全部工作,就将在 `src/lib.rs` 完成了。 咦!这可是干了很多活了,还好现在已经为将来的成功做好了准备。现在处理错误就容易多了,同时令到代码更具模块性。从现在开始,几乎咱们的全部工作,就将在 `src/lib.rs` 完成了。
下面就来通过运用现在这种新发现的模组性优势,完成一些对于早先不具模组性代码较难实现,而对这新代码却易于实现的事情。 下面就来通过运用现在这种新发现的模组性优势,完成一些对于早先不具模组性代码较难实现,而对这新代码却易于实现的事情。
End

View File

@ -101,3 +101,8 @@ How dreary to be somebody!
本章回顾了到目前为止曾学过的一些主要概念,并涵盖了在 Rust 中怎样完成常见 I/O 操作。经由使用命令行参数、文件、环境变量,以及那个用于打印错误的 `eprintln!` 宏,现在就已准备好编写命令行应用程序了。结合先前那些章中的概念,咱们所编写的代码将是良好组织、以恰当数据结构有效地存储着数据、对错误加以优美地处理,并被妥善地测试过。 本章回顾了到目前为止曾学过的一些主要概念,并涵盖了在 Rust 中怎样完成常见 I/O 操作。经由使用命令行参数、文件、环境变量,以及那个用于打印错误的 `eprintln!` 宏,现在就已准备好编写命令行应用程序了。结合先前那些章中的概念,咱们所编写的代码将是良好组织、以恰当数据结构有效地存储着数据、对错误加以优美地处理,并被妥善地测试过。
接下来,这里将探讨受函数式编程所影响的一些 Rust 特性闭包与迭代器closures and iterators 接下来,这里将探讨受函数式编程所影响的一些 Rust 特性闭包与迭代器closures and iterators
End

View File

@ -287,3 +287,8 @@ How dreary to be somebody!
相当棒!这里已经构建了一个经典工具自己的小型版本,并掌握了很多有关如何建构应用程序的知识。这里还了解到有关文件输入输出、生命周期、测试及命令行参数解析等方面的点滴内容。 相当棒!这里已经构建了一个经典工具自己的小型版本,并掌握了很多有关如何建构应用程序的知识。这里还了解到有关文件输入输出、生命周期、测试及命令行参数解析等方面的点滴内容。
而为了完善这个项目接下来就主要会演示怎样使用环境变量以及怎样打印到标准错误输出print to standard error在编写命令行程序时这两方面的知识都是有用的。 而为了完善这个项目接下来就主要会演示怎样使用环境变量以及怎样打印到标准错误输出print to standard error在编写命令行程序时这两方面的知识都是有用的。
End

View File

@ -41,3 +41,8 @@ mdbook serve ~/rust-lang-zh_CN -p 8080 -n 127.0.0.1 --open
此时,将在操作系统的默认浏览器中,打开本书。 此时,将在操作系统的默认浏览器中,打开本书。
End

View File

@ -106,3 +106,8 @@ impl AveragedCollection {
由于继承通常有着共用了超出必要代码的风险,时至今日,其已在许多编程语言中,作为编程设计模式而失宠了。子类本不应共用其父类的全部特征,但在继承父类时却会这样做。这就会造成程序的设计有较低的灵活性。由于子类从父类继承的一些方法并不适用于子类,因此继承还会引入调用子类上无意义或引发错误方法的可能。此外,一些语言还只将运行单一继承(即子类只能从一个类继承),这进一步限制了程序设计的灵活度。 由于继承通常有着共用了超出必要代码的风险,时至今日,其已在许多编程语言中,作为编程设计模式而失宠了。子类本不应共用其父类的全部特征,但在继承父类时却会这样做。这就会造成程序的设计有较低的灵活性。由于子类从父类继承的一些方法并不适用于子类,因此继承还会引入调用子类上无意义或引发错误方法的可能。此外,一些语言还只将运行单一继承(即子类只能从一个类继承),这进一步限制了程序设计的灵活度。
由于这些原因Rust 便采取了运用特质对象,而非继承的方法。接下来就要看看特质对象是如何实现 Rust 中的多态。 由于这些原因Rust 便采取了运用特质对象,而非继承的方法。接下来就要看看特质对象是如何实现 Rust 中的多态。
End

View File

@ -521,3 +521,8 @@ fn main() {
在读完这一章之后,不论咱们认为或是不认为 Rust 是门面向对象语言,现在都明白,咱们可以在 Rust 中使用特质对象来获得一些面向对象的特性。动态调遣dynamic dispatch 可以些许运行时性能损失换取到咱们代码一定程度的灵活性。咱们则可运用这样的灵活性来实现能有助于代码可维护性的一些面向对象模式。Rust 还有面向对象语言所没有的其他一些特性,比如所有权等。对于利用 Rust 各种长处方面的优势来讲,面向对象模式将不总是最佳方式,但其为一种可行选项。 在读完这一章之后,不论咱们认为或是不认为 Rust 是门面向对象语言,现在都明白,咱们可以在 Rust 中使用特质对象来获得一些面向对象的特性。动态调遣dynamic dispatch 可以些许运行时性能损失换取到咱们代码一定程度的灵活性。咱们则可运用这样的灵活性来实现能有助于代码可维护性的一些面向对象模式。Rust 还有面向对象语言所没有的其他一些特性,比如所有权等。对于利用 Rust 各种长处方面的优势来讲,面向对象模式将不总是最佳方式,但其为一种可行选项。
接下来,咱们将看看各种模式,这是带来大量灵活性的 Rust 诸多特性的另一项。虽然贯穿本书,咱们已经粗略地看了看他们,但仍尚未见识到他们的完整能力。咱们就拭目以待吧! 接下来,咱们将看看各种模式,这是带来大量灵活性的 Rust 诸多特性的另一项。虽然贯穿本书,咱们已经粗略地看了看他们,但仍尚未见识到他们的完整能力。咱们就拭目以待吧!
End

View File

@ -233,3 +233,8 @@ error: could not compile `simple_gui` due to previous error
回顾第 10 章中 [“运用了泛型的代码性能问题”](Ch10_Generic_Types_Traits_and_Lifetimes.md#使用泛型参数代码的性能问题) 小节中在泛型之上运用特质边界时咱们关于由编译器所完成的单一化过程the monomorphization process 的讨论:编译器会为咱们在泛型参数处,用到的各个具体类型,而产生出非通用的函数及方法实现。单一化过程所产生的代码,便是在进行 *静态调遣static dispatch*,这是编译器清楚,咱们在编译时调用的为哪个方法时的情况。这与 *动态调遣dynamic dispatch* 是相反的,动态调遣是编译器在编译时,无法区分出咱们所调用的为何方法时的情况。在动态调遣情况下,编译器产生出将在运行时,得出要调用方法的代码。 回顾第 10 章中 [“运用了泛型的代码性能问题”](Ch10_Generic_Types_Traits_and_Lifetimes.md#使用泛型参数代码的性能问题) 小节中在泛型之上运用特质边界时咱们关于由编译器所完成的单一化过程the monomorphization process 的讨论:编译器会为咱们在泛型参数处,用到的各个具体类型,而产生出非通用的函数及方法实现。单一化过程所产生的代码,便是在进行 *静态调遣static dispatch*,这是编译器清楚,咱们在编译时调用的为哪个方法时的情况。这与 *动态调遣dynamic dispatch* 是相反的,动态调遣是编译器在编译时,无法区分出咱们所调用的为何方法时的情况。在动态调遣情况下,编译器产生出将在运行时,得出要调用方法的代码。
在咱们运用特质对象时Rust 就必须使用动态调遣。对于全部可能与用到特质对象代码一起使用的类型编译器并无掌握因此他就不明白要调用何种类型上的哪个方法。相反在运行时Rust 会使用特质对象内部的指针,来掌握要调用哪个方法。这种做法会导致静态调遣下所不会发生的运行时开销。动态调遣还会阻止编译器内联某个方法代码的抉择,这就相应地阻止了一些优化。然而,咱们却真切地获得了,如同咱们在清单 17-5 中所编写的代码那样的灵活性,同时才能够支持清单 17-9 中那样的情况如此其便是一种需要考量的取舍了。when we use trait objects, Rust must use dynamic dispatch. The compiler doesn't know all the types that might be used with the code that's using trait objects, so it doesn't know which method implemented on which type to call. Instead, at runtime, Rust uses the pointers inside the trait object to know which method to call. This lookup incurs a runtime cost that doesn't occur with static dispatch. Dynamic dispatch also prevents the compiler from choosing to inline a method's code, which in turn prevents some optimizations. However, we did get extra flexibility in the code that we wrote in Listing 17-5 and were able to support in Listing 17-9, so it's a trade-off to consider. 在咱们运用特质对象时Rust 就必须使用动态调遣。对于全部可能与用到特质对象代码一起使用的类型编译器并无掌握因此他就不明白要调用何种类型上的哪个方法。相反在运行时Rust 会使用特质对象内部的指针,来掌握要调用哪个方法。这种做法会导致静态调遣下所不会发生的运行时开销。动态调遣还会阻止编译器内联某个方法代码的抉择,这就相应地阻止了一些优化。然而,咱们却真切地获得了,如同咱们在清单 17-5 中所编写的代码那样的灵活性,同时才能够支持清单 17-9 中那样的情况如此其便是一种需要考量的取舍了。when we use trait objects, Rust must use dynamic dispatch. The compiler doesn't know all the types that might be used with the code that's using trait objects, so it doesn't know which method implemented on which type to call. Instead, at runtime, Rust uses the pointers inside the trait object to know which method to call. This lookup incurs a runtime cost that doesn't occur with static dispatch. Dynamic dispatch also prevents the compiler from choosing to inline a method's code, which in turn prevents some optimizations. However, we did get extra flexibility in the code that we wrote in Listing 17-5 and were able to support in Listing 17-9, so it's a trade-off to consider.
End

View File

@ -475,3 +475,8 @@ fn calculate_length(s: String) -> (String, usize) {
*清单 4-5返回参数的所有权* *清单 4-5返回参数的所有权*
但是对于一个本应很常见的概念来说这样做太过仪式化和工作量都太大了。幸运的是Rust 有一种使用某个值,而不转移所有权的特性,叫做 *引用references* 但是对于一个本应很常见的概念来说这样做太过仪式化和工作量都太大了。幸运的是Rust 有一种使用某个值,而不转移所有权的特性,叫做 *引用references*
End

View File

@ -360,3 +360,8 @@ fn dangle() -> String {
接下来,我们来看看另一种引用:切片。 接下来,我们来看看另一种引用:切片。
End

View File

@ -347,3 +347,8 @@ fn main() {
所有权、借用和切片的概念,确保了 Rust 程序在编译时的内存安全。Rust 给到了咱们,与其他系统编程语言同样方式的,对咱们内存使用的掌控,但在数据的所有者超出作用域时,会让数据的所有者,自动清理该数据,这意味着咱们不必编写和调试额外代码,来获得这种控制。 所有权、借用和切片的概念,确保了 Rust 程序在编译时的内存安全。Rust 给到了咱们,与其他系统编程语言同样方式的,对咱们内存使用的掌控,但在数据的所有者超出作用域时,会让数据的所有者,自动清理该数据,这意味着咱们不必编写和调试额外代码,来获得这种控制。
所有权会影响 Rust 许多其他部分的工作方式,因此我们将在本书的其余部分,进一步讨论这些概念。我们来继续阅读第 5 章,看看如何在 `struct` 中,对数据块进行分组。 所有权会影响 Rust 许多其他部分的工作方式,因此我们将在本书的其余部分,进一步讨论这些概念。我们来继续阅读第 5 章,看看如何在 `struct` 中,对数据块进行分组。
End

View File

@ -149,3 +149,8 @@ crate
该树显示了其中一些模组是如何嵌套在另一模组中的;例如,`hosting` 嵌套在 `front_of_house` 中。该树还显示其中一些模组彼此属于 *同辈siblings*,即他们被定义在同一模组中;`hosting` 和 `serving``front_of_house` 中定义的同辈份模组。如果模组 A 包含在模组 B 中,我们就说模组 A 是模组 B 的子模组,而模组 B 是模组 A 的父模组。请注意,整个模组树的根,都位于名为 `crate` 的隐式模组下。 该树显示了其中一些模组是如何嵌套在另一模组中的;例如,`hosting` 嵌套在 `front_of_house` 中。该树还显示其中一些模组彼此属于 *同辈siblings*,即他们被定义在同一模组中;`hosting` 和 `serving``front_of_house` 中定义的同辈份模组。如果模组 A 包含在模组 B 中,我们就说模组 A 是模组 B 的子模组,而模组 B 是模组 A 的父模组。请注意,整个模组树的根,都位于名为 `crate` 的隐式模组下。
模组树可能会让咱们联想到电脑上的文件系统目录树;这是个非常恰当的比较!就像文件系统中的目录一样,咱们可以使用模组来组织代码。而就像目录中的文件一样,我们需要一种找到咱们模组的方法。 模组树可能会让咱们联想到电脑上的文件系统目录树;这是个非常恰当的比较!就像文件系统中的目录一样,咱们可以使用模组来组织代码。而就像目录中的文件一样,我们需要一种找到咱们模组的方法。
End

View File

@ -33,3 +33,8 @@ main.rs
运行 `cargo new` 后,我们使用 `ls` 查看 Cargo 创建了什么。在该项目目录中,有个 `Cargo.toml` 文件,给到我们一个包。还有个包含了 `main.rs``src` 目录。请用咱们的文本编辑器,打开 `Cargo.toml`,注意其中没有提到 `src/main.rs`。Cargo 遵循,`src/main.rs` 是与该软件包同名的二进制代码箱的代码箱根这一惯例。同样Cargo 知道,如果包目录中包含 `src/lib.rs`,那么该包中就包含一个,与该包同名的库代码箱,而 `src/lib.rs` 就是其代码箱根。Cargo 会将代码箱根文件,传递给 `rustc` 以构建出该库或二进制程序。 运行 `cargo new` 后,我们使用 `ls` 查看 Cargo 创建了什么。在该项目目录中,有个 `Cargo.toml` 文件,给到我们一个包。还有个包含了 `main.rs``src` 目录。请用咱们的文本编辑器,打开 `Cargo.toml`,注意其中没有提到 `src/main.rs`。Cargo 遵循,`src/main.rs` 是与该软件包同名的二进制代码箱的代码箱根这一惯例。同样Cargo 知道,如果包目录中包含 `src/lib.rs`,那么该包中就包含一个,与该包同名的库代码箱,而 `src/lib.rs` 就是其代码箱根。Cargo 会将代码箱根文件,传递给 `rustc` 以构建出该库或二进制程序。
这里,我们有着一个只包含 `src/main.rs` 的包,意味着他只包含一个名为 `my-project` 的二进制代码箱。如果某个包包含 `src/main.rs``src/lib.rs`,那么他就有两个代码箱:一个二进制代码箱和一个库代码箱,且两个代码箱都有着与该包同样的名字。通过在 `src/bin` 目录中放置一些文件,包可以有多个二进制代码箱:每个文件都将是个单独的二进制代码箱。 这里,我们有着一个只包含 `src/main.rs` 的包,意味着他只包含一个名为 `my-project` 的二进制代码箱。如果某个包包含 `src/main.rs``src/lib.rs`,那么他就有两个代码箱:一个二进制代码箱和一个库代码箱,且两个代码箱都有着与该包同样的名字。通过在 `src/bin` 目录中放置一些文件,包可以有多个二进制代码箱:每个文件都将是个单独的二进制代码箱。
End

View File

@ -323,3 +323,8 @@ pub fn eat_at_restaurant() {
因为我们将这个 `Appetizer` 枚举构造为了公开,所以我们可以在 `eat_at_restaurant` 中,使用 `Soup``Salad` 两个变种。 因为我们将这个 `Appetizer` 枚举构造为了公开,所以我们可以在 `eat_at_restaurant` 中,使用 `Soup``Salad` 两个变种。
除非枚举变种是公开的,否则枚举的用处就不大;如果每次都要给所有枚举变种注释上 `pub`,那就太烦人了,所以枚举变种默认是公开的。通常结构体在其字段不公开的情况下也很有用,因此结构体字段遵循了一般规则,即除非被注释为 `pub`,否则默认情况下所有字段,都是私有的。 除非枚举变种是公开的,否则枚举的用处就不大;如果每次都要给所有枚举变种注释上 `pub`,那就太烦人了,所以枚举变种默认是公开的。通常结构体在其字段不公开的情况下也很有用,因此结构体字段遵循了一般规则,即除非被注释为 `pub`,否则默认情况下所有字段,都是私有的。
End

View File

@ -84,3 +84,8 @@ pub fn add_to_waitlist() {}
Rust 实现了包拆分为多个代码箱,进而将代码箱拆分为多个模组,这样就可以从一个模组,对定义在另一模组中的程序项目加以引用。通过指明绝对或相对路径,就可以做到这点。使用 `use` 语句,就可以将这些程序项目的路径,带入到作用域,如此就可以在那个作用域中,多次用到所带入的程序项目时,使用较简短的路径。默认下模组代码是私有的,但可通过添加 `pub` 关键字,而将一些定义构造为公开的。 Rust 实现了包拆分为多个代码箱,进而将代码箱拆分为多个模组,这样就可以从一个模组,对定义在另一模组中的程序项目加以引用。通过指明绝对或相对路径,就可以做到这点。使用 `use` 语句,就可以将这些程序项目的路径,带入到作用域,如此就可以在那个作用域中,多次用到所带入的程序项目时,使用较简短的路径。默认下模组代码是私有的,但可通过添加 `pub` 关键字,而将一些定义构造为公开的。
下一章中就会看看可在本地组织良好代码中使用到的标准库中的一些集合数据结构collection data structures 下一章中就会看看可在本地组织良好代码中使用到的标准库中的一些集合数据结构collection data structures
End

View File

@ -304,3 +304,8 @@ use std::collections::*;
这条 `use` 语句会将 `std::collections` 中定义的所有公开项目引入当前作用域。使用全局操作符时要当心!全局性会使咱们更难分辨,哪些名称是在作用域中,以及程序中使用的名字是在何处定义。 这条 `use` 语句会将 `std::collections` 中定义的所有公开项目引入当前作用域。使用全局操作符时要当心!全局性会使咱们更难分辨,哪些名称是在作用域中,以及程序中使用的名字是在何处定义。
全局操作符通常在测试时使用,以便将所有被测试内容引入 `tests` 模块;我们将在第 11 章 [“如何编写测试”](../automated_tests/howto.md#怎样编写测试) 小节中讨论这个问题。全局操作符有时也作为前奏模式the prelude pattern的一部分使用有关该模式的更多信息请参阅 [标准库文档](https://doc.rust-lang.org/std/prelude/index.html#other-preludes)。 全局操作符通常在测试时使用,以便将所有被测试内容引入 `tests` 模块;我们将在第 11 章 [“如何编写测试”](../automated_tests/howto.md#怎样编写测试) 小节中讨论这个问题。全局操作符有时也作为前奏模式the prelude pattern的一部分使用有关该模式的更多信息请参阅 [标准库文档](https://doc.rust-lang.org/std/prelude/index.html#other-preludes)。
End

View File

@ -240,3 +240,8 @@ fn main() {
由于如咱们在第 13 章中曾讨论过的,闭包与函数类似,咱们也可以函数参数清单中的这同样方式,在闭包参数清单中使用模式。 由于如咱们在第 13 章中曾讨论过的,闭包与函数类似,咱们也可以函数参数清单中的这同样方式,在闭包参数清单中使用模式。
到这里咱们就已经看到了运用模式的数种方式但在咱们可使用他们的每种地方模式并非以同样方式运作。在一些地方模式必须是确凿的must be irrefutable而在别的情况下他们则可以是可证伪的can be refutable。接下来咱们就将讨论这两个概念。 到这里咱们就已经看到了运用模式的数种方式但在咱们可使用他们的每种地方模式并非以同样方式运作。在一些地方模式必须是确凿的must be irrefutable而在别的情况下他们则可以是可证伪的can be refutable。接下来咱们就将讨论这两个概念。
End

View File

@ -89,3 +89,8 @@ warning: `refutable_demo` (bin "refutable_demo") generated 1 warning
由于这个原因除了应以一个不可证伪模式匹配全部剩余值的最后支臂外其他那些匹配支臂就必须使用可证伪模式。Rust 允许咱们在仅有一个支臂的 `match` 中,使用不可证伪模式,但这种语法不是特别有用,并可以一个更简单的 `let` 语句替换。 由于这个原因除了应以一个不可证伪模式匹配全部剩余值的最后支臂外其他那些匹配支臂就必须使用可证伪模式。Rust 允许咱们在仅有一个支臂的 `match` 中,使用不可证伪模式,但这种语法不是特别有用,并可以一个更简单的 `let` 语句替换。
现在,咱们就知道了哪些地方要使用模式,以及可证伪与不可证伪模式的区别,下面就来介绍所有可用于创建模式的语法。 现在,咱们就知道了哪些地方要使用模式,以及可证伪与不可证伪模式的区别,下面就来介绍所有可用于创建模式的语法。
End

View File

@ -666,3 +666,8 @@ fn main() {
Rust 的模式,在区分不同类别数据方面非常有用。当在 `match` 表达式中用到模式时Rust 就会确保咱们的那些模式,涵盖每个可能的值,否则咱们的程序便不会编译。`let` 语句与函数参数中的模式,会令到这两种结构更为有用,在实现值解构为一些更小的部分的同时,赋值给一些变量。咱们可以创建出简单抑或复杂的模式,来适合咱们的需求。 Rust 的模式,在区分不同类别数据方面非常有用。当在 `match` 表达式中用到模式时Rust 就会确保咱们的那些模式,涵盖每个可能的值,否则咱们的程序便不会编译。`let` 语句与函数参数中的模式,会令到这两种结构更为有用,在实现值解构为一些更小的部分的同时,赋值给一些变量。咱们可以创建出简单抑或复杂的模式,来适合咱们的需求。
接下来,作为本书倒数第二章,咱们将数种 Rust 特性中,一些高级的方面。 接下来,作为本书倒数第二章,咱们将数种 Rust 特性中,一些高级的方面。
End

View File

@ -46,3 +46,8 @@ fn main() {
``` ```
Rust 还有另一种注释即文档注释documentation comments我们将在第 14 章 [“将 Crate 发布到 Crates.io”](../crates-io/publishing.md) 一节中讨论。 Rust 还有另一种注释即文档注释documentation comments我们将在第 14 章 [“将 Crate 发布到 Crates.io”](../crates-io/publishing.md) 一节中讨论。
End

View File

@ -719,3 +719,8 @@ fn main() {
``` ```
</details> </details>
End

View File

@ -435,3 +435,8 @@ error: process didn't exit successfully: `target\debug\tuple_demo.exe` (exit cod
该程序在索引操作中,使用某个无效值时,出现了 *运行时* 错误。程序以一条错误信息退出了,并且没有执行最后的那条 `println!` 语句。当咱们尝试使用索引访问某个元素时Rust 会检查咱们指定的索引是否小于数组长度。如果索引大于或等于长度Rust 就会终止运行。这种检查必须在运行时进行,尤其是在这种情况下,因为编译器不可能知道,某名用户在他们稍后运行代码时,会输入什么值。 该程序在索引操作中,使用某个无效值时,出现了 *运行时* 错误。程序以一条错误信息退出了,并且没有执行最后的那条 `println!` 语句。当咱们尝试使用索引访问某个元素时Rust 会检查咱们指定的索引是否小于数组长度。如果索引大于或等于长度Rust 就会终止运行。这种检查必须在运行时进行,尤其是在这种情况下,因为编译器不可能知道,某名用户在他们稍后运行代码时,会输入什么值。
这是 Rust 内存安全原则实际应用的一个例子。在许多底层语言中并无这种检查而当咱们提供了某个不正确的索引时无效内存就会被访问到。Rust 通过立即退出,而不是允许这种内存访问并继续,保护咱们免受此类错误的影响。第 9 章将讨论更多的 Rust 错误处理,以及如何编写既不会终止运行,也不允许无效内存访问的,可读安全代码。 这是 Rust 内存安全原则实际应用的一个例子。在许多底层语言中并无这种检查而当咱们提供了某个不正确的索引时无效内存就会被访问到。Rust 通过立即退出,而不是允许这种内存访问并继续,保护咱们免受此类错误的影响。第 9 章将讨论更多的 Rust 错误处理,以及如何编写既不会终止运行,也不允许无效内存访问的,可读安全代码。
End

View File

@ -347,3 +347,8 @@ error: could not compile `functions` (bin "functions") due to previous error
其中的主要错误信息,`mismatched types`,揭示了这段代码的核心问题。函数 `plus_one` 的定义,说他将返回一个 `i32`,但语句不会计算为某个值,而是由 `()` 表示的单元值the unit type。因此没有返回任何值这与函数定义相矛盾而导致一个报错。在此输出中Rust 提供了一条,可能有助于纠正此问题的信息:他建议删除分号,这就将会修复这个错误。 其中的主要错误信息,`mismatched types`,揭示了这段代码的核心问题。函数 `plus_one` 的定义,说他将返回一个 `i32`,但语句不会计算为某个值,而是由 `()` 表示的单元值the unit type。因此没有返回任何值这与函数定义相矛盾而导致一个报错。在此输出中Rust 提供了一条,可能有助于纠正此问题的信息:他建议删除分号,这就将会修复这个错误。
End

View File

@ -227,3 +227,8 @@ error: could not compile `variables` (bin "variables") due to previous error
现在我们已经探讨了变量的工作原理,我们来看看,他们可以拥有的更多数据类型。 现在我们已经探讨了变量的工作原理,我们来看看,他们可以拥有的更多数据类型。
End

View File

@ -181,3 +181,8 @@ fn main() {
匣子仅提供这种间接与内存堆的内存分配;他们不具备任何像咱们在其他灵巧指针类型中,将看到的其他特别能力。他们也没有这些特殊能力所带来的性能开销,所以在像构造列表这样的情况下,他们就能很有用,因为间接性是我们唯一需要的功能。在第 17 章,咱们还会看一下匣子的更多用例。 匣子仅提供这种间接与内存堆的内存分配;他们不具备任何像咱们在其他灵巧指针类型中,将看到的其他特别能力。他们也没有这些特殊能力所带来的性能开销,所以在像构造列表这样的情况下,他们就能很有用,因为间接性是我们唯一需要的功能。在第 17 章,咱们还会看一下匣子的更多用例。
`Box<T>` 类型是一个智能指针,因为他实现了 `Deref` 特质,他允许 `Box<T>` 值被当作引用。当 `Box<T>` 值超出作用域时,由于 `Drop` 特质的实现,匣子所指向的内存堆数据也会被清理。这两个特质对于咱们在本章后面将讨论的其他灵巧指针所提供的功能,将更加重要。咱们来更深入地探讨这两个特质。 `Box<T>` 类型是一个智能指针,因为他实现了 `Deref` 特质,他允许 `Box<T>` 值被当作引用。当 `Box<T>` 值超出作用域时,由于 `Drop` 特质的实现,匣子所指向的内存堆数据也会被清理。这两个特质对于咱们在本章后面将讨论的其他灵巧指针所提供的功能,将更加重要。咱们来更深入地探讨这两个特质。
End

View File

@ -270,3 +270,8 @@ fn main() {
前两种情况彼此相同,只是第二种情况实现了可变性。第一种情况表明,如果咱们有一个 `&T`,并且 `T` 实现了对某种类型 `U``Deref`,咱们可以透明地得到一个 `&U`。第二种情况表明相同的解引用强制转换发生在可变引用上。 前两种情况彼此相同,只是第二种情况实现了可变性。第一种情况表明,如果咱们有一个 `&T`,并且 `T` 实现了对某种类型 `U``Deref`,咱们可以透明地得到一个 `&U`。第二种情况表明相同的解引用强制转换发生在可变引用上。
第三种情况比较棘手Rust 还会将可变引用强制转换为不可变引用。但反过来是 *不* 可行的不可变引用永远不会强制转换为可变引用。由于借用规则如果咱们有一个可变引用则该可变引用必须是对那个数据的唯一引用否则程序将无法编译。将一个可变引用转换为一个不可变引用永远不会违反借用规则。将不可变引用转换为可变引用则要求那个初始不可变引用是对那个数据的唯一不可变引用但借用规则并不能保证这一点。因此Rust 不能假设将不可变引用转换为可变引用是可行的。 第三种情况比较棘手Rust 还会将可变引用强制转换为不可变引用。但反过来是 *不* 可行的不可变引用永远不会强制转换为可变引用。由于借用规则如果咱们有一个可变引用则该可变引用必须是对那个数据的唯一引用否则程序将无法编译。将一个可变引用转换为一个不可变引用永远不会违反借用规则。将不可变引用转换为可变引用则要求那个初始不可变引用是对那个数据的唯一不可变引用但借用规则并不能保证这一点。因此Rust 不能假设将不可变引用转换为可变引用是可行的。
End

Some files were not shown because too many files have changed in this diff Show More