diff --git a/docs/print.html b/docs/print.html
index bc57858..2c0ed6a 100644
--- a/docs/print.html
+++ b/docs/print.html
@@ -2,7 +2,7 @@
@@ -10344,6 +10344,127 @@ fn main() {
阅读本章后,不管你是否认为 Rust 是一个面向对象语言,现在你都见识了 trait 对象是一个 Rust 中获取部分面向对象功能的方法。动态分发可以通过牺牲一些运行时性能来为你的代码提供一些灵活性。这些灵活性可以用来实现有助于代码可维护性的面向对象模式。Rust 也有像所有权这样不同于面向对象语言的功能。面向对象模式并不总是利用 Rust 实力的最好方式。
接下来,让我们看看另一个提供了很多灵活性的 Rust 功能:模式。贯穿本书我们都曾简单的见过他们,但并没有见识过他们的全部本领。让我们开始吧!
+
+
+ch18-00-patterns.md
+
+commit 3d47ebddad51b0080a19857e1495675a8e9376ef
+
+
模式是 Rust 中特殊的语法,它用来匹配类型中的结构,无论类型是简单还是复杂。模式由一些常量组成;解构数组、枚举、结构体或者是元组;变量、通配符和占位符。这些部分描述了我们要处理的数据的“形状”。
+
我们通过将一些值与模式相比较来使用它。如果模式匹配这些值,我们对值部分进行相应处理。回忆一下第六章讨论 match
表达式时像硬币分类器那样使用模式。我们可以为形状中的片段命名,就像在第六章中命名出现在二十五美分硬币上的州那样,如果数据符合这个形状,就可以使用这些命名的片段。
+
本章是所有模式相关内容的参考。我们将涉及到使用模式的有效位置,refutable 与 irrefutable 模式的区别,和你可能会见到的不同类型的模式语法。
+
+
+ch18-01-all-the-places-for-patterns.md
+
+commit 4ca9e513e532a4d229ab5af7dfcc567129623bf4
+
+
模式出现在 Rust 的很多地方。你已经在不经意间使用了很多模式!本部分是一个所有有效模式位置的参考。
+
+
如第六章所讨论的,一个模式常用的位置是 match
表达式的分支。在形式上 match
表达式由 match
关键字、用于匹配的值和一个或多个分支构成。这些分支包含一个模式和在值匹配分支的模式时运行的表达式:
+
match VALUE {
+ PATTERN => EXPRESSION,
+ PATTERN => EXPRESSION,
+ PATTERN => EXPRESSION,
+}
+
+
+
match
表达式必须是穷尽的。当我们把所有分支的模式都放在一起,match
表达式所有可能的值都应该被考虑到。一个确保覆盖每个可能值的方法是在最后一个分支使用捕获所有的模式,比如一个变量名。一个匹配任何值的名称永远也不会失败,因此可以覆盖之前分支模式匹配剩下的情况。
+
这有一个额外的模式经常被用于结尾的分支:_
。它匹配所有情况,不过它从不绑定任何变量。这在例如只希望在某些模式下运行代码而忽略其他值的时候很有用。
+
+
第六章讨论过了 if let
表达式,以及它是如何成为编写等同于只关心一个情况的 match
语句的简写的。if let
可以对应一个可选的 else
和代码在 if let
中的模式不匹配时运行。
+
列表 18-1 展示了甚至可以组合并匹配 if let
、else if
和 else if let
。这些代码展示了一系列针对不同条件的检查来决定背景颜色应该是什么。为了达到这个例子的目的,我们创建了硬编码值的变量,在真实程序中则可能由询问用户获得。如果用户指定了中意的颜色,我们将使用它作为背景颜色。如果今天是星期二,背景颜色将是绿色。如果用户指定了他们的年龄字符串并能够成功将其解析为数字的话,我们将根据这个数字使用紫色或者橙色。最后,如果没有一个条件符合,背景颜色将是蓝色:
+
文件名: src/main.rs
+
fn main() {
+ let favorite_color: Option<&str> = None;
+ let is_tuesday = false;
+ let age: Result<u8, _> = "34".parse();
+
+ if let Some(color) = favorite_color {
+ println!("Using your favorite color, {}, as the background", color);
+ } else if is_tuesday {
+ println!("Tuesday is green day!");
+ } else if let Ok(age) = age {
+ if age > 30 {
+ println!("Using purple as the background color");
+ } else {
+ println!("Using orange as the background color");
+ }
+ } else {
+ println!("Using blue as the background color");
+ }
+}
+
+
列表 18-1: 结合 if let
、else if
、else if let
和 else
+
这个条件结构允许我们支持复杂的需求。使用这里硬编码的值,例子会打印出 Using purple as the background color
。
+
注意 if let
也可以像 match
分支那样引入覆盖变量:if let Ok(age) = age
引入了一个新的覆盖变量 age
,它包含 Ok
成员中的值。这也意味着 if age > 30
条件需要位于这个代码块内部;不能将两个条件组合为 if let Ok(age) = age && age > 30
,因为我们希望与 30 进行比较的被覆盖的 age
直到大括号开始的新作用域才是有效的。
+
另外注意这样有很多情况的条件并没有 match
表达式强大,因为其穷尽性没有为编译器所检查。如果去掉最后的 else
块而遗漏处理一些情况,编译器也不会报错。这个例子可能过于复杂以致难以重写为一个可读的 match
,所以需要额外注意处理了所有的情况,因为编译器不会为我们检查穷尽性。
+
+
一个与 if let
类似的结构体是 while let
:它允许只要模式匹配就一直进行 while
循环。列表 18-2 展示了一个使用 while let
的例子,它使用 vector 作为栈并打以先进后出的方式打印出 vector 中的值:
+
let mut stack = Vec::new();
+
+stack.push(1);
+stack.push(2);
+stack.push(3);
+
+while let Some(top) = stack.pop() {
+ println!("{}", top);
+}
+
+
列表 18-2: 使用 while let
循环只要 stack.pop()
返回 Some
就打印出其值
+
这个例子会打印出 3、2 和 1。pop
方法取出 vector 的最后一个元素并返回Some(value)
,如果 vector 是空的,它返回 None
。while
循环只要 pop
返回 Some
就会一直运行其块中的代码。一旦其返回 None
,while
循环停止。我们可以使用 while let
来弹出栈中的每一个元素。
+
+
for
循环,如同第三章所讲的,是 Rust 中最常见的循环结构。那一章所没有讲到的是 for
可以获取一个模式。列表 18-3 中展示了如何使用 for
循环来解构一个元组。enumerate
方法适配一个迭代器来产生元组,其包含值和值的索引:
+
let v = vec![1, 2, 3];
+
+for (index, value) in v.iter().enumerate() {
+ println!("{} is at index {}", value, index);
+}
+
+
列表 18-3: 在 for
循环中使用模式来解构 enumerate
返回的元组
+
这会打印出:
+
1 is at index 0
+2 is at index 1
+3 is at index 2
+
+
第一个 enumerate
调用会产生元组 (0, 1)
。当这个匹配模式 (index, value)
,index
将会是 0 而 value
将会是 1。
+
+
match
和 if let
都是本书之前明确讨论过的使用模式的位置,不过他们不是仅有的使用过模式的地方。例如,考虑一下这个直白的 let
变量赋值:
+
let x = 5;
+
+
本书进行了不下百次这样的操作。你可能没有发觉,不过你这正是在使用模式!let
语句更为正式的样子如下:
+
let PATTERN = EXPRESSION;
+
+
我们见过的像 let x = 5;
这样的语句中变量名位于 PATTERN
位置;变量名不过是形式特别朴素的模式。
+
通过 let
,我们将表达式与模式比较,并为任何找到的名称赋值。所以例如 let x = 5;
的情况,x
是一个模式代表“将匹配到的值绑定到变量 x”。同时因为名称 x
是整个模式,这个模式实际上等于“将任何值绑定到变量 x
,不过它是什么”。
+
为了更清楚的理解 let
的模式匹配的方面,考虑列表 18-4 中使用 let
和模式解构一个元组:
+
let (x, y, z) = (1, 2, 3);
+
+
列表 18-4: 使用模式解构元组并一次创建三个变量
+
这里有一个元组与模式匹配。Rust 会比较值 (1, 2, 3)
与模式 (x, y, z)
并发现值匹配这个模式。在这个例子中,将会把 1
绑定到 x
,2
绑定到 y
, 3
绑定到 z
。你可以将这个元组模式看作是将三个独立的变量模式结合在一起。
+
在第十六章中我们见过另一个解构元组的例子,列表 16-6 中,那里解构 mpsc::channel()
的返回值为 tx
(发送者)和 rx
(接收者)。
+
+
类似于 let
,函数参数也可以是模式。列表 18-5 中的代码声明了一个叫做 foo
的函数,它获取一个 i32
类型的参数 x
,这看起来应该很熟悉:
+
fn foo(x: i32) {
+ // code goes here
+}
+
+
列表 18-5: 在参数中使用模式的函数签名
+
x
部分就是一个模式!类似于之前对 let
所做的,可以在函数参数中匹配元组。列表 18-6 展示了如何可以将传递给函数的元组拆分为值:
+
文件名: src/main.rs
+
fn print_coordinates(&(x, y): &(i32, i32)) {
+ println!("Current location: ({}, {})", x, y);
+}
+
+fn main() {
+ let point = (3, 5);
+ print_coordinates(&point);
+}
+
+
列表 18-6: 一个在参数中解构元组的函数
+
这会打印出 Current location: (3, 5)
。当传递值 &(3, 5)
给 print_coordinates
时,这个值会匹配模式 &(x, y)
,x
得到了值 3,而 y
得到了值 5。
+
因为如第十三章所讲闭包类似于函数,也可以在闭包参数中使用模式。
+
在这些可以使用模式的位置中的一个区别是,对于 for
循环、let
和函数参数,其模式必须是 irrefutable 的。接下来让我们讨论这个。
diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index 9520f6b..cf6c5e7 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -96,4 +96,10 @@
- [什么是面向对象?](ch17-01-what-is-oo.md)
- [为使用不同类型的值而设计的 trait 对象](ch17-02-trait-objects.md)
- [面向对象设计模式的实现](ch17-03-oo-design-patterns.md)
-
\ No newline at end of file
+
+## 高级主题
+
+- [模式用来匹配值的结构](ch18-00-patterns.md)
+ - [所有可能会用到模式的位置](ch18-01-all-the-places-for-patterns.md)
+ - [refutable:何时模式可能会匹配失败](ch18-02-refutability.md)
+ - [模式的全部语法](ch18-03-pattern-syntax.md)
\ No newline at end of file
diff --git a/src/ch18-00-patterns.md b/src/ch18-00-patterns.md
new file mode 100644
index 0000000..ab9cec1
--- /dev/null
+++ b/src/ch18-00-patterns.md
@@ -0,0 +1,11 @@
+# 模式用来匹配值的结构
+
+> [ch18-00-patterns.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch18-00-patterns.md)
+>
+> commit 3d47ebddad51b0080a19857e1495675a8e9376ef
+
+模式是 Rust 中特殊的语法,它用来匹配类型中的结构,无论类型是简单还是复杂。模式由一些常量组成;解构数组、枚举、结构体或者是元组;变量、通配符和占位符。这些部分描述了我们要处理的数据的“形状”。
+
+我们通过将一些值与模式相比较来使用它。如果模式匹配这些值,我们对值部分进行相应处理。回忆一下第六章讨论 `match` 表达式时像硬币分类器那样使用模式。我们可以为形状中的片段命名,就像在第六章中命名出现在二十五美分硬币上的州那样,如果数据符合这个形状,就可以使用这些命名的片段。
+
+本章是所有模式相关内容的参考。我们将涉及到使用模式的有效位置,*refutable* 与 *irrefutable* 模式的区别,和你可能会见到的不同类型的模式语法。
diff --git a/src/ch18-01-all-the-places-for-patterns.md b/src/ch18-01-all-the-places-for-patterns.md
new file mode 100644
index 0000000..84fe08e
--- /dev/null
+++ b/src/ch18-01-all-the-places-for-patterns.md
@@ -0,0 +1,172 @@
+## 所有可能会用到模式的位置
+
+> [ch18-01-all-the-places-for-patterns.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch18-01-all-the-places-for-patterns.md)
+>
+> commit 4ca9e513e532a4d229ab5af7dfcc567129623bf4
+
+模式出现在 Rust 的很多地方。你已经在不经意间使用了很多模式!本部分是一个所有有效模式位置的参考。
+
+### `match` 分支
+
+如第六章所讨论的,一个模式常用的位置是 `match` 表达式的分支。在形式上 `match` 表达式由 `match` 关键字、用于匹配的值和一个或多个分支构成。这些分支包含一个模式和在值匹配分支的模式时运行的表达式:
+
+```
+match VALUE {
+ PATTERN => EXPRESSION,
+ PATTERN => EXPRESSION,
+ PATTERN => EXPRESSION,
+}
+```
+
+#### 穷尽性和默认模式 `_`
+
+`match` 表达式必须是穷尽的。当我们把所有分支的模式都放在一起,`match` 表达式所有可能的值都应该被考虑到。一个确保覆盖每个可能值的方法是在最后一个分支使用捕获所有的模式,比如一个变量名。一个匹配任何值的名称永远也不会失败,因此可以覆盖之前分支模式匹配剩下的情况。
+
+这有一个额外的模式经常被用于结尾的分支:`_`。它匹配所有情况,不过它从不绑定任何变量。这在例如只希望在某些模式下运行代码而忽略其他值的时候很有用。
+
+### `if let` 表达式
+
+第六章讨论过了 `if let` 表达式,以及它是如何成为编写等同于只关心一个情况的 `match` 语句的简写的。`if let` 可以对应一个可选的 `else` 和代码在 `if let` 中的模式不匹配时运行。
+
+列表 18-1 展示了甚至可以组合并匹配 `if let`、`else if` 和 `else if let`。这些代码展示了一系列针对不同条件的检查来决定背景颜色应该是什么。为了达到这个例子的目的,我们创建了硬编码值的变量,在真实程序中则可能由询问用户获得。如果用户指定了中意的颜色,我们将使用它作为背景颜色。如果今天是星期二,背景颜色将是绿色。如果用户指定了他们的年龄字符串并能够成功将其解析为数字的话,我们将根据这个数字使用紫色或者橙色。最后,如果没有一个条件符合,背景颜色将是蓝色:
+
+
+
+```rust
+fn main() {
+ let favorite_color: Option<&str> = None;
+ let is_tuesday = false;
+ let age: Result