Merge pull request #1 from KaiserY/master

同步
pull/236/head
huluwa 6 years ago committed by GitHub
commit ab572dba85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -98,7 +98,7 @@
- [共享状态](ch16-03-shared-state.md)
- [可扩展的并发:`Sync` 与 `Send`](ch16-04-extensible-concurrency-sync-and-send.md)
- [Rust 的面向对象编程特](ch17-00-oop.md)
- [Rust 的面向对象编程特](ch17-00-oop.md)
- [面向对象语言的特点](ch17-01-what-is-oo.md)
- [为使用不同类型的值而设计的 trait 对象](ch17-02-trait-objects.md)
- [面向对象设计模式的实现](ch17-03-oo-design-patterns.md)

@ -1,4 +1,4 @@
# 附录C - 可派生的 trait
## 附录C - 可派生的 trait
> [appendix-03-derivable-traits.md][appendix-03]
> <br />

@ -1,4 +1,4 @@
## 附录E: 本书翻译
## 附录E - 本书翻译
> [appendix-05-translation.md](https://github.com/rust-lang/book/blob/master/second-edition/src/appendix-05-translation.md)
> <br />

@ -1 +1,113 @@
## F - 最新功能
> [appendix-06-newest-features.md](https://github.com/rust-lang/book/blob/master/second-edition/src/appendix-06-newest-features.md)
> <br />
> commit b64de01431cdf1020ad3358d2f83e46af68a39ed
自从本书的主要部分完成之后,该附录文档中的特性已经加到 Rust 的稳定版中。
### 字段初始化缩写
我们可以通过具名字段来初始化一个数据结构(结构体、枚举、联合体),如将 `fieldname: fieldname` 缩写为 `fieldname` 。这可以以更少的重复代码来完成一个复杂的初始化语法。
```rust
#[derive(Debug)]
struct Person {
name: String,
age: u8,
}
fn main() {
let name = String::from("Peter");
let age = 27;
// Using full syntax:
let peter = Person { name: name, age: age };
let name = String::from("Portia");
let age = 27;
// Using field init shorthand:
let portia = Person { name, age };
println!("{:?}", portia);
}
```
## 从循环中返回( loop
`loop` 的用法之一是重试一个可以操作,比如检查线程是否完成其任务。然而可能需要将该操作的结果传到其他部分代码。如果加上 `break` 表达式来停止循环,则会从循环中断中返回:
```rust
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
assert_eq!(result, 20);
}
```
## `use` 声明中的内置组
如果有一个包含许多不同子模块的复杂模块树,然后需要从每个子模块中引入几个特性,那么将所有导入模块放在同一声明中来保持代码清洁同时避免根模块名重复将会非常有用。
`use` 声明所支持的嵌套在这些情况下对你有帮助:简单的导入和全局导入。例如,下面的代码片段导入了 `bar``Foo``baz` 中所有项和 `Bar`
```rust
# #![allow(unused_imports, dead_code)]
#
# mod foo {
# pub mod bar {
# pub type Foo = ();
# }
# pub mod baz {
# pub mod quux {
# pub type Bar = ();
# }
# }
# }
#
use foo::{
bar::{self, Foo},
baz::{*, quux::Bar},
};
#
# fn main() {}
```
## 范围包含
先前,当在表达式中使用范围( `..``...` )时,其必须使用排除上界的 `..` ,而在模式中,则要使用包含上界的 `...` 。而现在,`..=` 可作为语法用于表达式或范围上下文件中的包含范围中。
```rust
fn main() {
for i in 0 ..= 10 {
match i {
0 ..= 5 => println!("{}: low", i),
6 ..= 10 => println!("{}: high", i),
_ => println!("{}: out of range", i),
}
}
}
```
`...` 语法也可用在匹配语法中,但不能用于表达式中,而 `..=` 则二者皆可。
## 128 字节的整数
Rust 1.26.0 添加了 128 字节的整数基本类型:
- `u128`: 一个在 [0, 2^128 - 1] 范围内的 128 字节的无符号整数
- `i128`: 一个在 [-(2^127), 2^127 - 1] 范围内的有符号整数
这俩基本类型由 LLVM 支持高效地实现。即使在不支持 128 字节整数的平台上,它们都是可用的,且可像其他整数类型那样使用。
这俩基本类型在那些需要高效使用大整数的算法中非常有用,如某些加密算法。

@ -6,9 +6,9 @@
本章既是一个目前所学的很多技能的概括,也是一个更多标准库功能的探索。我们将构建一个与文件和命令行输入/输出交互的命令行工具来练习现在一些你已经掌握的 Rust 技能。
Rust 的运行速度、安全性、**单二进制文件** 输出和跨平台支持使其成为创建命令行程序的绝佳选择,所以我们的项目将创建一个我们自己版本的经典命令行工具:`grep`。grep 是 “**G**lobally search a **R**egular **E**xpression and **P**rint.” 的首字母缩写。`grep` 最简单的使用场景是在特定文件中搜索指定字符串。为此,`grep` 获取一个文件名和一个字符串作为参数,接着读取文件并找到其中包含字符串参数的行然后打印出这些行。
Rust 的运行速度、安全性、**单二进制文件** 输出和跨平台支持使其成为创建命令行程序的绝佳选择,所以我们的项目将创建一个我们自己版本的经典命令行工具:`grep`。grep 是 “**G**lobally search a **R**egular **E**xpression and **P**rint.” 的首字母缩写。`grep` 最简单的使用场景是在特定文件中搜索指定字符串。为此,`grep` 获取一个文件名和一个字符串作为参数,接着读取文件并找到其中包含字符串参数的行然后打印出这些行。
在这个过程中,我们会展示如何让我们的命令行工具利用很多命令行工具中用到的终端功能。读取环境变量来使得用户可以配置工具的行为。打印到标准错误控制流(`stderr` 而不是标准输出(`stdout`),例如这样用户可以选择将成功输出重定向到文件中仍然在屏幕上显示错误信息。
在这个过程中,我们会展示如何让我们的命令行工具利用很多命令行工具中用到的终端功能。读取环境变量来使得用户可以配置工具的行为。打印到标准错误控制流(`stderr` 而不是标准输出(`stdout`),例如这样用户可以选择将成功输出重定向到文件中的同时仍然在屏幕上显示错误信息。
一位 Rust 社区的成员Andrew Gallant已经创建了一个功能完整且非常快速的 `grep` 版本,叫做 `ripgrep`。相比之下,我们的 `grep` 版本将非常简单,本章将教会你一些帮助理解像 `ripgrep` 这样真实项目的背景知识。

@ -4,7 +4,7 @@
> <br>
> commit 97e60b3cb623d4a5b85419212b085ade8a11cbe1
一如之前使用 `cargo new` 新建一个项目我们称之为 `minigrep` 以便与可能已经安装在系统上的`grep`工具相区别:
一如之前使用 `cargo new` 新建一个项目我们称之为 `minigrep` 以便与可能已经安装在系统上的`grep`工具相区别:
```text
$ cargo new --bin minigrep
@ -18,7 +18,7 @@ $ cd minigrep
$ cargo run searchstring example-filename.txt
```
现在 `cargo new` 生成的程序忽略任何传递给它的参数。[Crates.io](https://crates.io/) 上有一些现成的库可以帮助我们接受命令行参数,不过因为正在学习,让我们自己来实现一个。
现在 `cargo new` 生成的程序忽略任何传递给它的参数。[Crates.io](https://crates.io/) 上有一些现成的库可以帮助我们接受命令行参数,不过我们正在学习这些内容,让我们自己来实现一个。
### 读取参数值
@ -60,7 +60,7 @@ $ cargo run needle haystack
["target/debug/minigrep", "needle", "haystack"]
```
注意 vector 的第一个值是 `"target/debug/minigrep"`,它是我们二进制文件的名称。这与 C 中的参数列表的行为相符合,并使得程序可以在执行过程中使用它的名字。能够访问程序名称在需要在信息中打印时,或者需要根据执行程序所使用的命令行别名来改变程序行为时显得很方便,不过考虑到本章的目的,我们将忽略它并只保存所需的两个参数。
注意 vector 的第一个值是 `"target/debug/minigrep"`,它是我们二进制文件的名称。这与 C 中的参数列表的行为相匹配,让程序使用在执行时调用它们的名称。如果要在消息中打印它或者根据用于调用程序的命令行别名更改程序的行为,通常可以方便地访问程序名称,不过考虑到本章的目的,我们将忽略它并只保存所需的两个参数。
### 将参数值保存进变量

@ -1,7 +1,12 @@
# Rust 是一个面向对象的编程语言吗?
# Rust 的面向对象特性
> [ch17-00-oop.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch17-00-oop.md)
> [ch17-00-oop.md][ch17-00]
> <br>
> commit 28d0efb644d18e8d104c2e813c8cdce50d040d3d
> commit 07b0ca8c829af09d60ab4eb9e69584b6f4a96f60
面向对象编程Object-Oriented Programming是一种起源于 20 世纪 60 年代的 Simula 编程语言的模式化编程方式,然后在 90 年代随着 C++ 语言开始流行。关于 OOP 是什么有很多相互矛盾的定义在一些定义下Rust 是面向对象的在其他定义下Rust 不是。在本章节中,我们会探索一些被普遍认为是面向对象的特性和这些特性是如何体现在 Rust 语言习惯中的。接着会展示如何在 Rust 中实现面向对象设计模式,并讨论这么做与利用 Rust 自身的一些优势实现的方案相比有什么取舍。
[ch17-00]: https://github.com/rust-lang/book/blob/master/second-edition/src/ch17-00-oop.md
[commit]: https://github.com/rust-lang/book/commit/07b0ca8c829af09d60ab4eb9e69584b6f4a96f60
面向对象编程Object-Oriented ProgrammingOOP
面向对象编程Object-Oriented ProgrammingOOP是一种起源于 20 世纪 60 年代的 Simula 编程语言的模式化编程方式,然后在 90 年代随着 C++ 语言开始流行。关于 OOP 是什么有很多相互矛盾的定义在一些定义下Rust 是面向对象的在其他定义下Rust 不是。在本章节中,我们会探索一些被普遍认为是面向对象的特性和这些特性是如何体现在 Rust 语言习惯中的。接着会展示如何在 Rust 中实现面向对象设计模式,并讨论这么做与利用 Rust 自身的一些优势实现的方案相比有什么取舍。

@ -18,10 +18,6 @@ had this to say about it https://www.martinfowler.com/bliki/GangOfFour.html:
`Design Patterns: Elements of Reusable Object-Oriented Software` 这本书被俗称为 `The Gang of Four book`,是面向对象编程模式的目录。它这样定义面向对象编程:
> Object-oriented programs are made up of objects. An *object* packages both
> data and the procedures that operate on that data. The procedures are
> typically called *methods* or *operations*.
>
> 面向对象的程序是由对象组成的。一个 **对象** 包含数据和操作这些数据的过程。这些过程通常被称为 **方法** 或 **操作**。
在这个定义下Rust 是面向对象的:结构体和枚举包含数据而 impl 块提供了在结构体和枚举之上的方法。虽然带有方法的结构体和枚举并不被 **称为** 对象,但是他们提供了与对象相同的功能,参考 Gang of Four 中对象的定义。

@ -280,7 +280,7 @@ a little bit /Carol -->
- 返回值类型不为 `Self`
- 方法没有任何泛型类型参数
`Self` 关键字是我们要实现 trait 或方法的类型的别名。对象安全对于 trait 对象是必须的,因为一旦有了 trait 对象,就不再知晓实现该 trait 的具体类型是什么了。如果 trait 方法返回具体的 `Self` 类型,但是 trait 对象忘记了其真正的类型,那么方法不可能使用已经忘却的原始具体类型。同理对于泛型类型参数来说,当使用 trait 时其会放入具体的类型参数:此具体类型编程了实现改 trait 的类型的一部分。当使用 trait 对象时其具体类型被抹去了,故无从得知放入泛型参数类型的类型是什么。
`Self` 关键字是我们要实现 trait 或方法的类型的别名。对象安全对于 trait 对象是必须的,因为一旦有了 trait 对象,就不再知晓实现该 trait 的具体类型是什么了。如果 trait 方法返回具体的 `Self` 类型,但是 trait 对象忘记了其真正的类型,那么方法不可能使用已经忘却的原始具体类型。同理对于泛型类型参数来说,当使用 trait 时其会放入具体的类型参数:此具体类型变成了实现该 trait 的类型的一部分。当使用 trait 对象时其具体类型被抹去了,故无从得知放入泛型参数类型的类型是什么。
一个 trait 的方法不是对象安全的例子是标准库中的 `Clone` trait。`Clone` trait 的 `clone` 方法的参数签名看起来像这样:

@ -49,7 +49,7 @@ caveats that the reader needs to be aware of when working with raw pointers.
You'd choose to use raw pointers to do something that you can't do with smart
pointers or references. I've tried to clarify above /Carol -->
示例 19-1 展示了如何从引用同时创建不可变和可变裸指针。
示例 19-1 展示了如何从引用同时创建不可变和可变裸指针。
```rust
let mut num = 5;

@ -16,7 +16,7 @@ newtype 模式可以用于一些其他我们还未讨论的功能,包括静态
新类型也可以隐藏其内部的泛型类型。例如,可以提供一个封装了 `HashMap<i32, String>``People` 类型,用来储存人名以及相应的 ID。使用 `People` 的代码只需与提供的公有 API 交互即可,比如向 `People` 集合增加名字字符串的方法,这样这些代码就无需知道在内部我们将一个 `i32` ID 赋予了这个名字了。newtype 模式是一种实现第十七章 “封装隐藏了实现细节” 部分所讨论的隐藏实现细节的封装的轻量级方法。
newtype 也可以隐藏其内部的泛型类型。例如,可以提供一个封装了 `HashMap<i32, String>``People` 类型,用来储存人名以及相应的 ID。使用 `People` 的代码只需与提供的公有 API 交互即可,比如向 `People` 集合增加名字字符串的方法,这样这些代码就无需知道在内部我们将一个 `i32` ID 赋予了这个名字了。newtype 模式是一种实现第十七章 “封装隐藏了实现细节” 部分所讨论的隐藏实现细节的封装的轻量级方法。
### 类型别名用来创建类型同义词

@ -65,7 +65,7 @@ changing too much -->
**线程池***thread pool*)是一组预先分配的等待或准备处理任务的线程。当程序收到一个新任务,线程池中的一个线程会被分配任务,这个线程会离开并处理任务。其余的线程则可用于处理在第一个线程处理任务的同时处理其他接收到的任务。当第一个线程处理完任务时,它会返回空闲线程池中等待处理新任务。线程池允许我们并发处理连接,增加 server 的吞吐量。
我们会将池中线程限制为较少的数量以防拒绝服务Denial of Service DoS攻击如果程序为每一个接收的请求都新建一个线程某人向 server 发起千万级的请求请求时会耗尽服务器的资源并导致所有请求的处理都被终止。
我们会将池中线程限制为较少的数量以防拒绝服务Denial of Service DoS攻击如果程序为每一个接收的请求都新建一个线程某人向 server 发起千万级的请求时会耗尽服务器的资源并导致所有请求的处理都被终止。
不同于分配无限的线程,线程池中将有固定数量的等待线程。当新进请求时,将请求发送到线程池中做处理。线程池会维护一个接收请求的队列。每一个线程会从队列中取出一个请求,处理请求,接着向对队列索取另一个请求。通过这种设计,则可以并发处理 `N` 个请求,其中 `N` 为线程数。如果每一个线程都在响应慢请求,之后的请求仍然会阻塞队列,不过相比之前增加了能处理的慢请求的数量。

Loading…
Cancel
Save