From 535afd0c88861f2b2cf3411322545d2303dc4cc4 Mon Sep 17 00:00:00 2001 From: icey-self Date: Fri, 9 Aug 2019 23:12:24 +0800 Subject: [PATCH 01/16] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=8A=A0=E9=80=9F?= =?UTF-8?q?=E6=9F=A5=E7=9C=8B=E7=AB=99=E7=82=B9=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 38dd95e..0eb55e7 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,6 @@ vuepress dev ./src 本翻译主要采用 [mdBook](https://github.com/rust-lang-nursery/mdBook) 格式。同时支持 [GitBook](https://github.com/GitbookIO/gitbook),但会缺失部分功能,如一些代码没有语法高亮。 -本翻译加速查看站点[上海站点http://rustdoc.saigao.fun](http://rustdoc.saigao.fun) +本翻译加速查看站点[上海站点http://rustdoc.saigao.fun](http://rustdoc.saigao.fun),[深圳站点http://120.78.128.153/rustbook](http://120.78.128.153/rustbook) [GitBook.com](https://www.gitbook.com/) 地址:[https://legacy.gitbook.com/book/kaisery/trpl-zh-cn/details](https://legacy.gitbook.com/book/kaisery/trpl-zh-cn/details) From 2c084ad428b1724eac2c1efe422ba62c15c9fff5 Mon Sep 17 00:00:00 2001 From: KaiserY Date: Tue, 13 Aug 2019 09:50:26 +0800 Subject: [PATCH 02/16] update ch04-02 close #325 --- src/ch04-02-references-and-borrowing.md | 59 +++++++++++++++++-------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/src/ch04-02-references-and-borrowing.md b/src/ch04-02-references-and-borrowing.md index d0be48c..f79947c 100644 --- a/src/ch04-02-references-and-borrowing.md +++ b/src/ch04-02-references-and-borrowing.md @@ -2,7 +2,7 @@ > [ch04-02-references-and-borrowing.md](https://github.com/rust-lang/book/blob/master/src/ch04-02-references-and-borrowing.md) >
-> commit a86c1d315789b3ca13b20d50ad5005c62bdd9e37 +> commit 6c0d83499c8e77e06a71d28c5e1adccec278d4f3 示例 4-5 中的元组代码有这样一个问题:我们必须将 `String` 返回给调用函数,以便在调用 `calculate_length` 后仍能使用 `String`,因为 `String` 被移动到了 `calculate_length` 内。 @@ -130,14 +130,15 @@ println!("{}, {}", r1, r2); ```text error[E0499]: cannot borrow `s` as mutable more than once at a time - --> src/main.rs:5:10 + --> src/main.rs:5:14 | -4 | let r1 = &mut s; - | ------ first mutable borrow occurs here -5 | let r2 = &mut s; - | ^^^^^^ second mutable borrow occurs here -6 | println!("{}, {}", r1, r2); - | -- borrow later used here +4 | let r1 = &mut s; + | ------ first mutable borrow occurs here +5 | let r2 = &mut s; + | ^^^^^^ second mutable borrow occurs here +6 | +7 | println!("{}, {}", r1, r2); + | -- first borrow later used here ``` 这个限制允许可变性,不过是以一种受限制的方式允许。新 Rustacean 们经常与此作斗争,因为大部分语言中变量任何时候都是可变的。 @@ -168,9 +169,9 @@ let r2 = &mut s; ```rust,ignore,does_not_compile let mut s = String::from("hello"); -let r1 = &s; // no problem -let r2 = &s; // no problem -let r3 = &mut s; // BIG PROBLEM +let r1 = &s; // 没问题 +let r2 = &s; // 没问题 +let r3 = &mut s; // 大问题 println!("{}, {}, and {}", r1, r2, r3); ``` @@ -179,20 +180,40 @@ println!("{}, {}, and {}", r1, r2, r3); ```text error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable - --> src/main.rs:6:10 + --> src/main.rs:6:14 | -4 | let r1 = &s; // no problem - | -- immutable borrow occurs here -5 | let r2 = &s; // no problem -6 | let r3 = &mut s; // BIG PROBLEM - | ^^^^^^ mutable borrow occurs here +4 | let r1 = &s; // 没问题 + | -- immutable borrow occurs here +5 | let r2 = &s; // 没问题 +6 | let r3 = &mut s; // 大问题 + | ^^^^^^ mutable borrow occurs here 7 | -8 | println!("{}, {}, and {}", r1, r2, r3); - | -- borrow later used here +8 | println!("{}, {}, and {}", r1, r2, r3); + | -- immutable borrow later used here ``` 哇哦!我们 **也** 不能在拥有不可变引用的同时拥有可变引用。不可变引用的用户可不希望在他们的眼皮底下值就被意外的改变了!然而,多个不可变引用是可以的,因为没有哪个只能读取数据的人有能力影响其他人读取到的数据。 +注意一个引用的作用域从声明的地方开始一直持续到最后一次使用为止。例如,因为最后一次使用不可变引用在声明可变引用之前,所以如下代码是可以编译的: + + + +```rust,edition2018,ignore +let mut s = String::from("hello"); + +let r1 = &s; // 没问题 +let r2 = &s; // 没问题 +println!("{} and {}", r1, r2); +// 此位置之后 r1 和 r2 不再使用 + +let r3 = &mut s; // 没问题 +println!("{}", r3); +``` + +不可变引用 `r1` 和 `r2` 的作用域在 `println!` 最后一次使用之后结束,这也是创建可变引用 `r3` 的地方。它们的作用域没有重叠,所以代码是可以编译的。 + 尽管这些错误有时使人沮丧,但请牢记这是 Rust 编译器在提前指出一个潜在的 bug(在编译时而不是在运行时)并精准显示问题所在。这样你就不必去跟踪为何数据并不是你想象中的那样。 ### 悬垂引用(Dangling References) From a3ae3fbe6b0d27e4a12f7c46b7fa3ab3f132e297 Mon Sep 17 00:00:00 2001 From: Rustin <1196089730@qq.com> Date: Thu, 15 Aug 2019 08:31:45 +0800 Subject: [PATCH 03/16] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=BF=BB=E8=AF=91?= =?UTF-8?q?=E9=94=99=E5=88=AB=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit “将当编写一个其实现会”,修改“为将当编写一个其实先会”。 --- src/ch09-02-recoverable-errors-with-result.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch09-02-recoverable-errors-with-result.md b/src/ch09-02-recoverable-errors-with-result.md index 049a668..4efa276 100644 --- a/src/ch09-02-recoverable-errors-with-result.md +++ b/src/ch09-02-recoverable-errors-with-result.md @@ -194,7 +194,7 @@ thread 'main' panicked at 'Failed to open hello.txt: Error { repr: Os { code: ### 传播错误 -当编写一个其实现会调用一些可能会失败的操作的函数时,除了在这个函数中处理错误外,还可以选择让调用者知道这个错误并决定该如何处理。这被称为 **传播**(*propagating*)错误,这样能更好的控制代码调用,因为比起你代码所拥有的上下文,调用者可能拥有更多信息或逻辑来决定应该如何处理错误。 +当编写一个其实先会调用一些可能会失败的操作的函数时,除了在这个函数中处理错误外,还可以选择让调用者知道这个错误并决定该如何处理。这被称为 **传播**(*propagating*)错误,这样能更好的控制代码调用,因为比起你代码所拥有的上下文,调用者可能拥有更多信息或逻辑来决定应该如何处理错误。 例如,示例 9-6 展示了一个从文件中读取用户名的函数。如果文件不存在或不能读取,这个函数会将这些错误返回给调用它的代码: From 26750654f5d25e976f1a14637e959430d3101a9f Mon Sep 17 00:00:00 2001 From: icey-self Date: Thu, 15 Aug 2019 14:19:50 +0800 Subject: [PATCH 04/16] =?UTF-8?q?Revert=20"=E4=BF=AE=E5=A4=8D=E7=BF=BB?= =?UTF-8?q?=E8=AF=91=E9=94=99=E5=88=AB=E5=AD=97"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ch09-02-recoverable-errors-with-result.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch09-02-recoverable-errors-with-result.md b/src/ch09-02-recoverable-errors-with-result.md index 4efa276..049a668 100644 --- a/src/ch09-02-recoverable-errors-with-result.md +++ b/src/ch09-02-recoverable-errors-with-result.md @@ -194,7 +194,7 @@ thread 'main' panicked at 'Failed to open hello.txt: Error { repr: Os { code: ### 传播错误 -当编写一个其实先会调用一些可能会失败的操作的函数时,除了在这个函数中处理错误外,还可以选择让调用者知道这个错误并决定该如何处理。这被称为 **传播**(*propagating*)错误,这样能更好的控制代码调用,因为比起你代码所拥有的上下文,调用者可能拥有更多信息或逻辑来决定应该如何处理错误。 +当编写一个其实现会调用一些可能会失败的操作的函数时,除了在这个函数中处理错误外,还可以选择让调用者知道这个错误并决定该如何处理。这被称为 **传播**(*propagating*)错误,这样能更好的控制代码调用,因为比起你代码所拥有的上下文,调用者可能拥有更多信息或逻辑来决定应该如何处理错误。 例如,示例 9-6 展示了一个从文件中读取用户名的函数。如果文件不存在或不能读取,这个函数会将这些错误返回给调用它的代码: From fef648f487cac98bac50e782572685d935eac164 Mon Sep 17 00:00:00 2001 From: Wangxiz Date: Sun, 18 Aug 2019 22:07:16 +0800 Subject: [PATCH 05/16] =?UTF-8?q?fix=20a=20typo:=20=E6=AD=A3=E6=95=B0=20->?= =?UTF-8?q?=20=E6=95=B4=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ch04-01-what-is-ownership.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch04-01-what-is-ownership.md b/src/ch04-01-what-is-ownership.md index 132cccc..205920c 100644 --- a/src/ch04-01-what-is-ownership.md +++ b/src/ch04-01-what-is-ownership.md @@ -134,7 +134,7 @@ let y = x; 示例 4-2:将变量 `x` 的整数值赋给 `y` -我们大致可以猜到这在干什么:“将 `5` 绑定到 `x`;接着生成一个值 `x` 的拷贝并绑定到 `y`”。现在有了两个变量,`x` 和 `y`,都等于 `5`。这也正是事实上发生了的,因为正数是有已知固定大小的简单值,所以这两个 `5` 被放入了栈中。 +我们大致可以猜到这在干什么:“将 `5` 绑定到 `x`;接着生成一个值 `x` 的拷贝并绑定到 `y`”。现在有了两个变量,`x` 和 `y`,都等于 `5`。这也正是事实上发生了的,因为整数是有已知固定大小的简单值,所以这两个 `5` 被放入了栈中。 现在看看这个 `String` 版本: From fc05a1ef151235b4593cf47cf4fe726738728300 Mon Sep 17 00:00:00 2001 From: icey-self Date: Tue, 20 Aug 2019 13:38:24 +0800 Subject: [PATCH 06/16] update VS Build Tool versions update according to official documentation. --- src/ch01-01-installation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch01-01-installation.md b/src/ch01-01-installation.md index 18ab73e..50efcba 100644 --- a/src/ch01-01-installation.md +++ b/src/ch01-01-installation.md @@ -46,10 +46,10 @@ $ export PATH="$HOME/.cargo/bin:$PATH" ### 在 Windows 上安装 `rustup` -在 Windows 上,前往 [https://www.rust-lang.org/install.html][install] 并按照说明安装 Rust。在安装过程的某个步骤,你会收到一个信息说明为什么需要安装 Visual Studio 2013 或更新版本的 C++ build tools。获取这些 build tools 最方便的方法是安装 [Build Tools for Visual Studio 2017][visualstudio]。这个工具在 “Other Tools and Frameworks” 部分。 +在 Windows 上,前往 [https://www.rust-lang.org/install.html][install] 并按照说明安装 Rust。在安装过程的某个步骤,你会收到一个信息说明为什么需要安装 Visual Studio 2013 或更新版本的 C++ build tools。获取这些 build tools 最方便的方法是安装 [Build Tools for Visual Studio 2019][visualstudio]。这个工具在 “Other Tools and Frameworks” 部分。 [install]: https://www.rust-lang.org/install.html -[visualstudio]: https://www.visualstudio.com/downloads/ +[visualstudio]: https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2019 本书的余下部分会使用能同时运行于 *cmd.exe* 和 PowerShell 的命令。如果存在特定差异,我们会解释使用哪一个。 From dd8cb4d6ec28dd08115d4213c7763d068ec499cf Mon Sep 17 00:00:00 2001 From: fooofei Date: Thu, 29 Aug 2019 18:17:40 +0800 Subject: [PATCH 07/16] =?UTF-8?q?ch09-02/map=5Ferr=20=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E9=94=99=E8=AF=AF=EF=BC=8C=E5=AF=B9=E9=BD=90=E8=8B=B1=E6=96=87?= =?UTF-8?q?=E5=8E=9F=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ch09-02-recoverable-errors-with-result.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ch09-02-recoverable-errors-with-result.md b/src/ch09-02-recoverable-errors-with-result.md index 049a668..2177c36 100644 --- a/src/ch09-02-recoverable-errors-with-result.md +++ b/src/ch09-02-recoverable-errors-with-result.md @@ -135,19 +135,19 @@ use std::fs::File; use std::io::ErrorKind; fn main() { - let f = File::open("hello.txt").map_err(|error| { + let f = File::open("hello.txt").unwrap_or_else(|error| { if error.kind() == ErrorKind::NotFound { File::create("hello.txt").unwrap_or_else(|error| { - panic!("Tried to create file but there was a problem: {:?}", error); + panic!("Problem creating the file: {:?}", error); }) } else { - panic!("There was a problem opening the file: {:?}", error); + panic!("Problem opening the file: {:?}", error); } }); } ``` -在阅读完第十三章后再回到这个例子,并查看标准库文档 `map_err` 和 `unwrap_or_else` 方法都做了什么操作。还有很多这类方法可以消除大量处理错误时嵌套的 `match` 表达式。 +在阅读完第十三章后再回到这个例子,并查看标准库文档 `unwrap_or_else` 方法都做了什么操作。在处理错误时,还有很多这类技巧可以消除大量嵌套的 `match` 表达式。 ### 失败时 panic 的简写:`unwrap` 和 `expect` From 06a8a1ba95d5e58997951d621351d38306d4831e Mon Sep 17 00:00:00 2001 From: Hu Shuai Date: Sat, 31 Aug 2019 12:03:22 +0800 Subject: [PATCH 08/16] update ch14-03 --- src/ch14-03-cargo-workspaces.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ch14-03-cargo-workspaces.md b/src/ch14-03-cargo-workspaces.md index 4c4463a..101218d 100644 --- a/src/ch14-03-cargo-workspaces.md +++ b/src/ch14-03-cargo-workspaces.md @@ -2,7 +2,7 @@ > [ch14-03-cargo-workspaces.md](https://github.com/rust-lang/book/blob/master/src/ch14-03-cargo-workspaces.md) >
-> commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f +> commit c084bdd9ee328e7e774df19882ccc139532e53d8 第十二章中,我们构建一个包含二进制 crate 和库 crate 的包。你可能会发现,随着项目开发的深入,库 crate 持续增大,而你希望将其进一步拆分成多个库 crate。对于这种情况,Cargo 提供了一个叫 **工作空间**(*workspaces*)的功能,它可以帮助我们管理多个相关的协同开发的包。 @@ -106,9 +106,9 @@ pub fn add_one(x: i32) -> i32 { add-one = { path = "../add-one" } ``` -工作空间中的 crate 不必相互依赖,所以仍需显式地表明工作空间中 crate 的依赖关系。 +cargo并不假定工作空间中的Crates会相互依赖,所以需要明确表明工作空间中 crate 的依赖关系。 -接下来,在 `adder` crate 中使用 `add-one` crate 的函数 `add_one`。打开 *adder/src/main.rs* 在顶部增加一行 `use` 将新 `add-one` 库 crate 引入作用域。接着修改 `main` 函数来调用 `add_one` 函数,如示例 14-7 所示: +接下来,在 `adder` crate 中使用 `add-one` crate 的函数 `add_one`。打开 *adder/src/main.rs* 在顶部增加一行 `use` 将新 `add-one` 库 crate 引入作用域。接着修改 `main` 函数来调用 `add_one` 函数,如示例 14-7 所示。 文件名: adder/src/main.rs @@ -255,7 +255,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out 输出显示了 `cargo test` 只运行了 `add-one` crate 的测试而没有运行 `adder` crate 的测试。 -如果你选择向 *https://crates.io/* 发布工作空间中的 crate,每一个工作空间中的 crate 将会单独发布。`cargo publish` 命令并没有 `--all` 或者 `-p` 参数,所以必须进入每一个 crate 的目录并运行 `cargo publish` 来发布工作空间中的每一个 crate。 +如果你选择向 [crates.io](https://crates.io/)发布工作空间中的 crate,每一个工作空间中的 crate 需要单独发布。`cargo publish` 命令并没有 `--all` 或者 `-p` 参数,所以必须进入每一个 crate 的目录并运行 `cargo publish` 来发布工作空间中的每一个 crate。 现在尝试以类似 `add-one` crate 的方式向工作空间增加 `add-two` crate 来作为更多的练习! From 7bbe7457a56863520392d307aeeedf0c1f84e8cb Mon Sep 17 00:00:00 2001 From: Hu Shuai Date: Tue, 3 Sep 2019 18:46:07 +0800 Subject: [PATCH 09/16] Update ch16-00-concurrency.md --- src/ch16-00-concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch16-00-concurrency.md b/src/ch16-00-concurrency.md index 84779e7..1274c23 100644 --- a/src/ch16-00-concurrency.md +++ b/src/ch16-00-concurrency.md @@ -6,7 +6,7 @@ 安全并高效的处理并发编程是 Rust 的另一个主要目标。**并发编程**(*Concurrent programming*),代表程序的不同部分相互独立的执行,而 **并行编程**(*parallel programming*)代表程序不同部分于同时执行,这两个概念随着计算机越来越多的利用多处理器的优势时显得愈发重要。由于历史原因,在此类上下文中编程一直是困难且容易出错的:Rust 希望能改变这一点。 -起初,Rust 团队认为确保内存安全和防止并发问题是两个分别需要不同方法应对的挑战。随着时间的推移,团队发现所有权和类型系统是一系列解决内存安全 **和** 并发问题的强有力的工具!通过改进所有权和类型检查,Rust 很多并发错误都是 **编译时** 错误,而非运行时错误。因此,相比花费大量时间尝试重现运行时并发 bug 出现的特定情况,Rust 会拒绝编译不正确的代码并提供解释问题的错误信息。因此,你可以在开发时而不是不慎部署到生产环境后修复代码。我们给 Rust 的这一部分起了一个绰号 **无畏并发**(*fearless concurrency*)。无畏并发令你的代码免于出现诡异的 bug 并可以轻松重构且无需担心会引入新的 bug。 +起初,Rust 团队认为确保内存安全和防止并发问题是两个分别需要不同方法应对的挑战。随着时间的推移,团队发现所有权和类型系统是一系列解决内存安全 **和** 并发问题的强有力的工具!通过利用所有权和类型检查,在 Rust 中很多并发错误都是 **编译时** 错误,而非运行时错误。因此,相比花费大量时间尝试重现运行时并发 bug 出现的特定情况,Rust 会拒绝编译不正确的代码并提供解释问题的错误信息。因此,你可以在开发时修复代码,而不是在部署到生产环境后修复代码。我们给 Rust 的这一部分起了一个绰号 **无畏并发**(*fearless concurrency*)。无畏并发令你的代码免于出现诡异的 bug 并可以轻松重构且无需担心会引入新的 bug。 > 注意:出于简洁的考虑,我们将很多问题归类为 **并发**,而不是更准确的区分 **并发和(或)并行**。如果这是一本专注于并发和/或并行的书,我们肯定会更加精确的。对于本章,当我们谈到 **并发** 时,请自行脑内替换为 **并发和(或)并行**。 From 687fbf930be70c1dff7997542dcda724a26e52ff Mon Sep 17 00:00:00 2001 From: Hu Shuai Date: Tue, 3 Sep 2019 19:52:22 +0800 Subject: [PATCH 10/16] Update ch16-01-threads.md --- src/ch16-01-threads.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch16-01-threads.md b/src/ch16-01-threads.md index 7dd70d3..b6ce94b 100644 --- a/src/ch16-01-threads.md +++ b/src/ch16-01-threads.md @@ -22,7 +22,7 @@ Rust 尝试缓和使用线程的负面影响。不过在多线程上下文中编 在当前上下文中,**运行时** 代表二进制文件中包含的由语言自身提供的代码。这些代码根据语言的不同可大可小,不过任何非汇编语言都会有一定数量的运行时代码。为此,通常人们说一个语言 “没有运行时”,一般意味着 “小运行时”。更小的运行时拥有更少的功能不过其优势在于更小的二进制输出,这使其易于在更多上下文中与其他语言相结合。虽然很多语言觉得增加运行时来换取更多功能没有什么问题,但是 Rust 需要做到几乎没有运行时,同时为了保持高性能必需能够调用 C 语言,这点也是不能妥协的。 -绿色线程的 M:N 模型更大的语言运行时来管理这些线程。为此,Rust 标准库只提供了 1:1 线程模型实现。Rust 是足够底层的语言,所以有相应的 crate 实现了 M:N 线程模型,如果你宁愿牺牲性能来换取例如更好的线程运行控制和更低的上下文切换成本。 +绿色线程的 M:N 模型需要更大的语言运行时来管理这些线程。为此,Rust 标准库只提供了 1:1 线程模型实现。因为 Rust 是足够底层的语言,有一些 crate 实现了 M:N 线程模型,如果你宁愿牺牲性能来换取例如更好的线程运行控制和更低的上下文切换成本。 现在我们明白了 Rust 中的线程是如何定义的,让我们开始探索如何使用标准库提供的线程相关的 API 吧。 From 0b540449124ff0e0f399be39c74ae0c2c600194f Mon Sep 17 00:00:00 2001 From: Hu Shuai Date: Wed, 4 Sep 2019 13:48:45 +0800 Subject: [PATCH 11/16] Update ch16-02-message-passing.md --- src/ch16-02-message-passing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch16-02-message-passing.md b/src/ch16-02-message-passing.md index 1c13865..f8b3fc5 100644 --- a/src/ch16-02-message-passing.md +++ b/src/ch16-02-message-passing.md @@ -4,7 +4,7 @@ >
> commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f -一个人气正在上升的确保安全并发的方式是 **消息传递**(*message passing*),这里线程或 actor 通过发送包含数据的消息来相互沟通。这个思想来源于 [Go 编程语言文档中](http://golang.org/doc/effective_go.html) 的口号:“不要共享内存来通讯;而是要通讯来共享内存。”(“Do not communicate by +一个日益流行的确保安全并发的方式是 **消息传递**(*message passing*),这里线程或 actor 通过发送包含数据的消息来相互沟通。这个思想来源于 [Go 编程语言文档中](http://golang.org/doc/effective_go.html) 的口号:“不要共享内存来通讯;而是要通讯来共享内存。”(“Do not communicate by sharing memory; instead, share memory by communicating.”) Rust 中一个实现消息传递并发的主要工具是 **通道**(*channel*),一个 Rust 标准库提供了其实现的编程概念。你可以将其想象为一个水流的通道,比如河流或小溪。如果你将诸如橡皮鸭或小船之类的东西放入其中,它们会顺流而下到达下游。 @@ -189,7 +189,7 @@ Got: the Got: thread ``` -因为在主线程中并没有任何暂停或位于 `for` 循环中用于等待的代码,所以可以说主线程是在等待从新建线程中接收值。 +因为主线程中的 `for` 循环里并没有任何暂停或等待的代码,所以可以说主线程是在等待从新建线程中接收值。 ### 通过克隆发送者来创建多个生产者 From fe4421d0547778e69d1b95274366ded3c4331bf5 Mon Sep 17 00:00:00 2001 From: Hu Shuai Date: Sat, 7 Sep 2019 16:24:52 +0800 Subject: [PATCH 12/16] Improve some translations. --- src/ch17-01-what-is-oo.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch17-01-what-is-oo.md b/src/ch17-01-what-is-oo.md index 00d0526..e927fbb 100644 --- a/src/ch17-01-what-is-oo.md +++ b/src/ch17-01-what-is-oo.md @@ -95,8 +95,8 @@ impl AveragedCollection { > 多态(Polymorphism) > > 很多人将多态描述为继承的同义词。不过它是一个有关可以用于多种类型的代码的更广泛的概念。对于继承来说,这些类型通常是子类。 -> Rust 则通过泛型来使得对多个不同类型的抽象成为可能,并通过 trait bounds 加强对这些类型所必须提供的内容的限制。这有时被称为 *bounded parametric polymorphism*。 +> Rust 则通过泛型来对不同的可能类型进行抽象,并通过 trait bounds 对这些类型所必须提供的内容施加约束。这有时被称为 *bounded parametric polymorphism*。 近来继承作为一种语言设计的解决方案在很多语言中失宠了,因为其时常带有共享多于所需的代码的风险。子类不应总是共享其父类的所有特征,但是继承却始终如此。如此会使程序设计更为不灵活,并引入无意义的子类方法调用,或由于方法实际并不适用于子类而造成错误的可能性。某些语言还只允许子类继承一个父类,进一步限制了程序设计的灵活性。 -因为这些原因,Rust 选择了一个不同的途径,使用 trait 对象替代继承。让我们看一下 Rust 中的 trait 对象是如何实现多态的。 +因为这些原因,Rust 选择了一个不同的途径,使用 trait 对象而不是继承。让我们看一下 Rust 中的 trait 对象是如何实现多态的。 From aea864bbb3c0e5f52260edd3f4bb9590ee065956 Mon Sep 17 00:00:00 2001 From: Hu Shuai Date: Sat, 7 Sep 2019 21:48:52 +0800 Subject: [PATCH 13/16] Update and improve some translations. --- src/ch17-02-trait-objects.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ch17-02-trait-objects.md b/src/ch17-02-trait-objects.md index 4184449..42dc25d 100644 --- a/src/ch17-02-trait-objects.md +++ b/src/ch17-02-trait-objects.md @@ -2,21 +2,21 @@ > [ch17-02-trait-objects.md](https://github.com/rust-lang/book/blob/master/src/ch17-02-trait-objects.md) >
-> commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f +> commit 426f3e4ec17e539ae9905ba559411169d303a031 在第八章中,我们谈到了 vector 只能存储同种类型元素的局限。示例 8-10 中提供了一个定义 `SpreadsheetCell` 枚举来储存整型,浮点型和文本成员的替代方案。这意味着可以在每个单元中储存不同类型的数据,并仍能拥有一个代表一排单元的 vector。这在当编译代码时就知道希望可以交替使用的类型为固定集合的情况下是完全可行的。 -然而有时,我们希望库用户在特定情况下能够扩展有效的类型集合。为了展示如何实现这一点,这里将创建一个图形用户接口(Graphical User Interface, GUI)工具的例子,其它通过遍历列表并调用每一个项目的 `draw` 方法来将其绘制到屏幕上 —— 此乃一个 GUI 工具的常见技术。我们将要创建一个叫做 `gui` 的库 crate,它含一个 GUI 库的结构。这个 GUI 库包含一些可供开发者使用的类型,比如 `Button` 或 `TextField`。在此之上,`gui` 的用户希望创建自定义的可以绘制于屏幕上的类型:比如,一个程序员可能会增加 `Image`,另一个可能会增加 `SelectBox`。 +然而有时,我们希望库用户在特定情况下能够扩展有效的类型集合。为了展示如何实现这一点,这里将创建一个图形用户接口(Graphical User Interface, GUI)工具的例子,它通过遍历列表并调用每一个项目的 `draw` 方法来将其绘制到屏幕上 —— 此乃一个 GUI 工具的常见技术。我们将要创建一个叫做 `gui` 的库 crate,它含一个 GUI 库的结构。这个 GUI 库包含一些可供开发者使用的类型,比如 `Button` 或 `TextField`。在此之上,`gui` 的用户希望创建自定义的可以绘制于屏幕上的类型:比如,一个程序员可能会增加 `Image`,另一个可能会增加 `SelectBox`。 -这个例子中并不会实现一个功能完善的 GUI 库,不过会展示其中各个部分是如何结合在一起的。编写库的时候,我们不可能知晓并定义所有其他程序员希望创建的类型。我们所知晓的是 `gui` 需要记录一系列不同类型的值,并需要能够对其中每一个值调用 `draw` 方法。这里无需知道调用 `draw` 方法时具体会发生什么,只需提供可供这些值调用的方法即可。 +这个例子中并不会实现一个功能完善的 GUI 库,不过会展示其中各个部分是如何结合在一起的。编写库的时候,我们不可能知晓并定义所有其他程序员希望创建的类型。我们所知晓的是 `gui` 需要记录一系列不同类型的值,并需要能够对其中每一个值调用 `draw` 方法。这里无需知道调用 `draw` 方法时具体会发生什么,只要该值会有那个方法可供我们调用。 在拥有继承的语言中,可以定义一个名为 `Component` 的类,该类上有一个 `draw` 方法。其他的类比如 `Button`、`Image` 和 `SelectBox` 会从 `Component` 派生并因此继承 `draw` 方法。它们各自都可以覆盖 `draw` 方法来定义自己的行为,但是框架会把所有这些类型当作是 `Component` 的实例,并在其上调用 `draw`。不过 Rust 并没有继承,我们得另寻出路。 ### 定义通用行为的 trait -为了实现 `gui` 所期望拥有的行为,定义一个 `Draw` trait,其包含名为 `draw` 的方法。接着可以定义一个存放 **trait 对象**(*trait object*) 的 vector。trait 对象指向一个实现了我们指定 trait 的类型实例。我们通过指定某些指针,比如 `&` 引用或 `Box` 智能指针,接着指定相关的 trait(第十九章 “动态大小类型” 部分会介绍 trait 对象必须使用指针的原因)。我们可以使用 trait 对象代替泛型或具体类型。任何使用 trait 对象的位置,Rust 的类型系统会在编译时确保任何在此上下文中使用的值会实现其 trait 对象的 trait。如此便无需在编译时就知晓所有可能的类型。 +为了实现 `gui` 所期望拥有的行为,定义一个 `Draw` trait,其包含名为 `draw` 的方法。接着可以定义一个存放 **trait 对象**(*trait object*) 的 vector。trait 对象指向一个实现了我们指定 trait 的类型的实例,以及一个用于在运行时查找该类型的trait方法的表。我们通过指定某种指针来创建 trait 对象,例如 `&` 引用或 `Box` 智能指针,还有 `dyn` keyword, 以及指定相关的 trait(第十九章 “动态大小类型和`Sized` Trait” 部分会介绍 trait 对象必须使用指针的原因)。我们可以使用 trait 对象代替泛型或具体类型。任何使用 trait 对象的位置,Rust 的类型系统会在编译时确保任何在此上下文中使用的值会实现其 trait 对象的 trait。如此便无需在编译时就知晓所有可能的类型。 -之前提到过,Rust 刻意不将结构体与枚举称为 “对象”,以便与其他语言中的对象相区别。在结构体或枚举中,结构体字段中的数据和 `impl` 块中的行为是分开的,不同于其他语言中将数据和行为组合进一个称为对象的概念中。trait 对象将数据和行为两者相结合,从这种意义上说 **则** 其更类似其他语言中的对象。不过 trait 对象不同于传统的对象,因为不能向 trait 对象增加数据。trait 对象并不像其他语言中的对象那么通用:其(trait 对象)具体的作用是允许对通用行为的抽象。 +之前提到过,Rust 刻意不将结构体与枚举称为 “对象”,以便与其他语言中的对象相区别。在结构体或枚举中,结构体字段中的数据和 `impl` 块中的行为是分开的,不同于其他语言中将数据和行为组合进一个称为对象的概念中。trait 对象将数据和行为两者相结合,从这种意义上说 **则** 其更类似其他语言中的对象。不过 trait 对象不同于传统的对象,因为不能向 trait 对象增加数据。trait 对象并不像其他语言中的对象那么通用:其(trait 对象)具体的作用是允许对通用行为进行抽象。 示例 17-3 展示了如何定义一个带有 `draw` 方法的 trait `Draw`: @@ -30,7 +30,7 @@ pub trait Draw { 示例 17-3:`Draw` trait 的定义 -因为第十章已经讨论过如何定义 trait,其语法看起来应该比较眼熟。接下来就是新内容了:实例 17-4 定义了一个存放了名叫 `components` 的 vector 的结构体 `Screen`。这个 vector 的类型是 `Box`,此为一个 trait 对象:它是 `Box` 中任何实现了 `Draw` trait 的类型的替身。 +因为第十章已经讨论过如何定义 trait,其语法看起来应该比较眼熟。接下来就是新内容了:实例 17-4 定义了一个存放了名叫 `components` 的 vector 的结构体 `Screen`。这个 vector 的类型是 `Box`,此为一个 trait 对象:它是 `Box` 中任何实现了 `Draw` trait 的类型的替身。 文件名: src/lib.rs @@ -97,7 +97,7 @@ impl Screen 这限制了 `Screen` 实例必须拥有一个全是 `Button` 类型或者全是 `TextField` 类型的组件列表。如果只需要同质(相同类型)集合,则倾向于使用泛型和 trait bound,因为其定义会在编译时采用具体类型进行单态化。 -另一方面,通过使用 trait 对象的方法,一个 `Screen` 实例可以存放一个既能包含 `Box