mirror of
https://github.com/KaiserY/trpl-zh-cn
synced 2025-02-22 20:22:18 +08:00
Merge pull request #279 from yue2388253/master
improve some translation
This commit is contained in:
commit
7d6e8b4774
@ -6,11 +6,11 @@
|
||||
|
||||
就像 `cargo run` 会编译代码并运行生成的二进制文件一样,`cargo test` 在测试模式下编译代码并运行生成的测试二进制文件。可以指定命令行参数来改变 `cargo test` 的默认行为。例如,`cargo test` 生成的二进制文件的默认行为是并行的运行所有测试,并截获测试运行过程中产生的输出,阻止他们被显示出来,使得阅读测试结果相关的内容变得更容易。
|
||||
|
||||
这些选项的一部分可以传递给 `cargo test`,而另一些则需要传递给生成的测试二进制文件。为了分隔两种类型的参数,首先列出传递给 `cargo test` 的参数,接着是分隔符 `--`,再之后是传递给测试二进制文件的参数。运行 `cargo test --help` 会告诉你 `cargo test` 的相关参数,而运行 `cargo test -- --help` 则会告诉你可以在分隔符 `--` 之后使用的相关参数。
|
||||
可以将一部分命令行参数传递给 `cargo test`,而将另外一部分传递给生成的测试二进制文件。为了分隔这两种参数,需要先列出传递给 `cargo test` 的参数,接着是分隔符 `--`,再之后是传递给测试二进制文件的参数。运行 `cargo test --help` 会提示 `cargo test` 的有关参数,而运行 `cargo test -- --help` 可以提示在分隔符 `--` 之后使用的有关参数。
|
||||
|
||||
### 并行或连续的运行测试
|
||||
|
||||
当运行多个测试时,他们默认使用线程来并行的运行。这意味着测试会更快的运行完毕,所以你可以更快的得到代码能否工作的反馈。因为测试是在同时运行的,你应该确保测试不能相互依赖,或依赖任何共享的状态,包括依赖共享的环境,比如当前工作目录或者环境变量。
|
||||
当运行多个测试时, Rust 默认使用线程来并行运行。这意味着测试会更快地运行完毕,所以你可以更快的得到代码能否工作的反馈。因为测试是在同时运行的,你应该确保测试不能相互依赖,或依赖任何共享的状态,包括依赖共享的环境,比如当前工作目录或者环境变量。
|
||||
|
||||
举个例子,每一个测试都运行一些代码,假设这些代码都在硬盘上创建一个 *test-output.txt* 文件并写入一些数据。接着每一个测试都读取文件中的数据并断言这个文件包含特定的值,而这个值在每个测试中都是不同的。因为所有测试都是同时运行的,一个测试可能会在另一个测试读写文件过程中修改了文件。那么第二个测试就会失败,并不是因为代码不正确,而是因为测试并行运行时相互干扰。一个解决方案是使每一个测试读写不同的文件;另一个解决方案是一次运行一个测试。
|
||||
|
||||
@ -107,13 +107,13 @@ failures:
|
||||
test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
|
||||
```
|
||||
|
||||
注意测试的输出和测试结果的输出是相互交叉的;这是由于测试是并行运行的,也就是上一部分讲到的。尝试一同使用 `--test-threads=1` 和 `--nocapture` 功能来看看输出是什么样子!
|
||||
注意测试的输出和测试结果的输出是相互交叉的,这是由于测试是并行运行的(见上一部分)。尝试一同使用 `--test-threads=1` 和 `--nocapture` 功能来看看输出是什么样子!
|
||||
|
||||
### 通过名称来运行测试的子集
|
||||
### 通过指定名字来运行部分测试
|
||||
|
||||
有时运行整个测试集会耗费很长时间。如果你负责特定位置的代码,你可能会希望只运行这些代码相关的测试。你可以向 `cargo test` 传递希望运行的测试的部分名称作为参数来选择运行哪些测试。
|
||||
有时运行整个测试集会耗费很长时间。如果你负责特定位置的代码,你可能会希望只运行与这些代码相关的测试。你可以向 `cargo test` 传递所希望运行的测试名称的参数来选择运行哪些测试。
|
||||
|
||||
为了展示如何运行测试的子集,示例 11-11 为 `add_two` 函数创建了三个测试,我们可以选择具体运行哪一个:
|
||||
为了展示如何运行部分测试,示例 11-11 为 `add_two` 函数创建了三个测试,我们可以选择具体运行哪一个:
|
||||
|
||||
<span class="filename">文件名: src/lib.rs</span>
|
||||
|
||||
@ -240,4 +240,4 @@ test expensive_test ... ok
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out
|
||||
```
|
||||
|
||||
通过控制运行哪些测试,你可以确保能够快速地运行 `cargo test` 。当某个时刻需要检查 `ignored` 测试的结果,而且你也有时间等待这个结果的话,就可以选择执行 `cargo test -- --ignored`。
|
||||
通过控制运行哪些测试,你可以确保能够快速地运行 `cargo test` 。当你需要运行 `ignored` 的测试时,可以执行 `cargo test -- --ignored`。
|
||||
|
@ -87,9 +87,9 @@ fn it_adds_two() {
|
||||
|
||||
<span class="caption">示例 11-13:一个 `adder` crate 中函数的集成测试</span>
|
||||
|
||||
我们在顶部增加了 `extern crate adder`,这在单元测试中是不需要的。这是因为每一个 `tests` 目录中的测试文件都是完全独立的 crate,所以需要在每一个文件中导入库。
|
||||
与单元测试不同,我们需要在文件顶部添加 `use adder`。这是因为每一个 `tests` 目录中的测试文件都是完全独立的 crate,所以需要在每一个文件中导入库。
|
||||
|
||||
并不需要将 *tests/integration_test.rs* 中的任何代码标注为 `#[cfg(test)]`。Cargo 对 `tests` 文件夹特殊处理并只会在运行 `cargo test` 时编译这个目录中的文件。现在就运行 `cargo test` 试试:
|
||||
并不需要将 *tests/integration_test.rs* 中的任何代码标注为 `#[cfg(test)]`。 `tests` 文件夹在 Cargo 中是一个特殊的文件夹, Cargo 只会在运行 `cargo test` 时编译这个目录中的文件。现在就运行 `cargo test` 试试:
|
||||
|
||||
```text
|
||||
$ cargo test
|
||||
@ -143,7 +143,7 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
|
||||
|
||||
将每个集成测试文件当作其自己的 crate 来对待,这更有助于创建单独的作用域,这种单独的作用域能提供更类似与最终使用者使用 crate 的环境。然而,正如你在第七章中学习的如何将代码分为模块和文件的知识,*tests* 目录中的文件不能像 *src* 中的文件那样共享相同的行为。
|
||||
|
||||
当你有一些在多个集成测试文件都会用到的帮助函数,而你尝试按照第七章 “将模块移动到其他文件” 部分的步骤将他们提取到一个通用的模块中时, *tests* 目录中不同文件的行为就会显得很明显。例如,如果我们创建了 *tests/common.rs* 文件并将一个名叫 `setup` 的函数放入其中,这里将放入一些我们希望能够在多个测试文件的多个测试函数中调用的代码:
|
||||
当你有一些在多个集成测试文件都会用到的帮助函数,而你尝试按照第七章 “将模块移动到其他文件” 部分的步骤将他们提取到一个通用的模块中时, *tests* 目录中不同文件的行为就会显得很明显。例如,如果我们可以创建 一个*tests/common.rs* 文件并创建一个名叫 `setup` 的函数,我们希望这个函数能被多个测试文件的测试函数调用:
|
||||
|
||||
<span class="filename">文件名: tests/common.rs</span>
|
||||
|
||||
@ -181,9 +181,9 @@ running 0 tests
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
|
||||
```
|
||||
|
||||
我们并不希望 `common` 出现在测试结果中并显示 `running 0 tests` 。我们只是希望能够在其他集成测试文件中分享一些代码罢了。
|
||||
我们并不想要`common` 出现在测试结果中显示 `running 0 tests` 。我们只是希望其能被其他多个集成测试文件中调用罢了。
|
||||
|
||||
为了避免 `common` 出现在测试输出中,我们将创建 *tests/common/mod.rs* ,而不是创建 *tests/common.rs* 。在第七章的 “模块文件系统规则” 部分,对于拥有子模块的模块文件使用了 *module_name/mod.rs* 命名规范,虽然这里 `common` 并没有子模块,但是这样命名告诉 Rust 不要将 `common` 看作一个集成测试文件。当将 `setup` 函数代码移动到 *tests/common/mod.rs* 并删除 *tests/common.rs* 文件之后,测试输出中将不会出现这一部分。*tests* 目录中的子目录不会被作为单独的 crate 编译或作为一个测试结果部分出现在测试输出中。
|
||||
为了不让 `common` 出现在测试输出中,我们将创建 *tests/common/mod.rs* ,而不是创建 *tests/common.rs* 。这是一种 Rust 的命名规范,这样命名告诉 Rust 不要将 `common` 看作一个集成测试文件。将 `setup` 函数代码移动到 *tests/common/mod.rs* 并删除 *tests/common.rs* 文件之后,测试输出中将不会出现这一部分。*tests* 目录中的子目录不会被作为单独的 crate 编译或作为一个测试结果部分出现在测试输出中。
|
||||
|
||||
一旦拥有了 *tests/common/mod.rs*,就可以将其作为模块以便在任何集成测试文件中使用。这里是一个 *tests/integration_test.rs* 中调用 `setup` 函数的 `it_adds_two` 测试的例子:
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
## 接受命令行参数
|
||||
## 接受命令行参数
|
||||
|
||||
> [ch12-01-accepting-command-line-arguments.md](https://github.com/rust-lang/book/blob/master/src/ch12-01-accepting-command-line-arguments.md)
|
||||
> <br>
|
||||
@ -45,9 +45,9 @@ fn main() {
|
||||
>
|
||||
> 注意 `std::env::args` 在其任何参数包含无效 Unicode 字符时会 panic。如果你需要接受包含无效 Unicode 字符的参数,使用 `std::env::args_os` 代替。这个函数返回 `OsString` 值而不是 `String` 值。这里出于简单考虑使用了 `std::env::args`,因为 `OsString` 值每个平台都不一样而且比 `String` 值处理起来更为复杂。
|
||||
|
||||
在 `main` 函数的第一行,我们调用了 `env::args`,并立即使用 `collect` 来创建了一个包含迭代器所有值的 vector。`collect` 可以被用来创建很多类型的集合,所以这里显式注明 `args` 的类型来指定我们需要一个字符串 vector。虽然在 Rust 中我们很少会需要注明类型,`collect` 就是一个经常需要注明类型的函数,因为 Rust 不能推断出你想要什么类型的集合。
|
||||
在 `main` 函数的第一行,我们调用了 `env::args`,并立即使用 `collect` 来创建了一个包含迭代器所有值的 vector。`collect` 可以被用来创建很多类型的集合,所以这里显式注明 `args` 的类型来指定我们需要一个字符串 vector。虽然在 Rust 中我们很少会需要注明类型,然而 `collect` 是一个经常需要注明类型的函数,因为 Rust 不能推断出你想要什么类型的集合。
|
||||
|
||||
最后,我们使用调试格式 `:?` 打印出 vector。让我们尝试不用参数运行代码,接着用两个参数:
|
||||
最后,我们使用调试格式 `:?` 打印出 vector。让我们尝试分别用两种方式(不包含参数和包含参数)运行代码:
|
||||
|
||||
```text
|
||||
$ cargo run
|
||||
|
@ -1,4 +1,4 @@
|
||||
## 读取文件
|
||||
## 读取文件
|
||||
|
||||
> [ch12-02-reading-a-file.md](https://github.com/rust-lang/book/blob/master/src/ch12-02-reading-a-file.md)
|
||||
> <br>
|
||||
@ -49,11 +49,11 @@ fn main() {
|
||||
|
||||
<span class="caption">示例 12-4:读取第二个参数所指定的文件内容</span>
|
||||
|
||||
首先,我们增加了更多的 `use` 语句来引入标准库中的相关部分:需要 `std::fs` 来处理文件。
|
||||
首先,我们增加了一个 `use` 语句来引入标准库中的相关部分:我们需要 `std::fs` 来处理文件。
|
||||
|
||||
在 `main` 中新增了一行语句:`fs::read_to_string` 接受 `filename`,打开文件,接着返回包含其内容的 `Result<String>`。
|
||||
|
||||
在这些代码之后,我们再次增加了临时的 `println!` 打印出读取文件后 `contents` 的值,这样就可以检查目前为止的程序能否工作。
|
||||
在这些代码之后,我们再次增加了临时的 `println!` 打印出读取文件之后 `contents` 的值,这样就可以检查目前为止的程序能否工作。
|
||||
|
||||
尝试运行这些代码,随意指定一个字符串作为第一个命令行参数(因为还未实现搜索功能的部分)而将 *poem.txt* 文件将作为第二个参数:
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
## 重构改进模块性和错误处理
|
||||
## 重构改进模块性和错误处理
|
||||
|
||||
> [ch12-03-improving-error-handling-and-modularity.md](https://github.com/rust-lang/book/blob/master/src/ch12-03-improving-error-handling-and-modularity.md)
|
||||
> <br>
|
||||
@ -10,7 +10,7 @@
|
||||
|
||||
这同时也关系到第二个问题:`search` 和 `filename` 是程序中的配置变量,而像 `f` 和 `contents` 则用来执行程序逻辑。随着 `main` 函数的增长,就需要引入更多的变量到作用域中,而当作用域中有更多的变量时,将更难以追踪每个变量的目的。最好能将配置变量组织进一个结构,这样就能使他们的目的更明确了。
|
||||
|
||||
第三个问题是如果打开文件失败我们使用 `expect` 来打印出错误信息,不过这个错误信息只是说 `file not found`。除了缺少文件之外还有很多打开文件可能失败的方式:例如,文件可能存在,不过可能没有打开它的权限。如果我们现在就出于这种情况,打印出的 `file not found` 错误信息就给了用户错误的建议!
|
||||
第三个问题是如果打开文件失败我们使用 `expect` 来打印出错误信息,不过这个错误信息只是说 `file not found`。除了缺少文件之外还有很多可以导致打开文件失败的方式:例如,文件可能存在,不过可能没有打开它的权限。如果我们现在就出于这种情况,打印出的 `file not found` 错误信息就给了用户错误的建议!
|
||||
|
||||
第四,我们不停的使用 `expect` 来处理不同的错误,如果用户没有指定足够的参数来运行程序,他们会从 Rust 得到 `index out of bounds` 错误,而这并不能明确的解释问题。如果所有的错误处理都位于一处这样将来的维护者在需要修改错误处理逻辑时就只需要考虑这一处代码。将所有的错误处理都放在一处也有助于确保我们打印的错误信息对终端用户来说是有意义的。
|
||||
|
||||
@ -106,7 +106,7 @@ fn parse_config(args: &[String]) -> Config {
|
||||
|
||||
<span class="caption">示例 12-6:重构 `parse_config` 返回一个 `Config` 结构体实例</span>
|
||||
|
||||
`parse_config` 的签名表明它现在返回一个 `Config` 值。在 `parse_config` 的函数体中,之前返回引用了 `args` 中 `String` 值的字符串 slice,现在我们选择定义 `Config` 来包含拥有所有权的 `String` 值。`main` 中的 `args` 变量是参数值的所有者并只允许 `parse_config` 函数借用他们,这意味着如果 `Config` 尝试获取 `args` 中值的所有权将违反 Rust 的借用规则。
|
||||
`parse_config` 的签名表明它现在返回一个 `Config` 值。在之前的 `parse_config` 函数体中,我们返回了引用 `args` 中 `String` 值的字符串 slice,现在我们定义 `Config` 来包含拥有所有权的 `String` 值。`main` 中的 `args` 变量是参数值的所有者并只允许 `parse_config` 函数借用他们,这意味着如果 `Config` 尝试获取 `args` 中值的所有权将违反 Rust 的借用规则。
|
||||
|
||||
还有许多不同的方式可以处理 `String` 的数据,而最简单但有些不太高效的方式是调用这些值的 `clone` 方法。这会生成 `Config` 实例可以拥有的数据的完整拷贝,不过会比储存字符串数据的引用消耗更多的时间和内存。不过拷贝数据使得代码显得更加直白因为无需管理引用的生命周期,所以在这种情况下牺牲一小部分性能来换取简洁性的取舍是值得的。
|
||||
|
||||
@ -330,7 +330,7 @@ fn run(config: Config) -> Result<(), Box<dyn Error>> {
|
||||
|
||||
这里我们做出了三个明显的修改。首先,将 `run` 函数的返回类型变为 `Result<(), Box<Error>>`。之前这个函数返回 unit 类型 `()`,现在它仍然保持作为 `Ok` 时的返回值。
|
||||
|
||||
对于错误类型,使用了 **trait 对象** `Box<dyn Error>`(在开头使用了 `use` 语句将 `std::error::Error` 引入作用域)。第十七章会涉及 trait 对象。目前只需知道 `Box<dyn Error>` 意味着函数会返回实现了 `Error` trait 的类型,不过无需指定具体将会返回的值的类型。这提供了在不同的错误场景可能有不同类型的错误返回值的灵活性。这也就是 `dyn`,它是 “动态”(“dynamic”)的缩写。
|
||||
对于错误类型,使用了 **trait 对象** `Box<dyn Error>`(在开头使用了 `use` 语句将 `std::error::Error` 引入作用域)。第十七章会涉及 trait 对象。目前只需知道 `Box<dyn Error>` 意味着函数会返回实现了 `Error` trait 的类型,不过无需指定具体将会返回的值的类型。这提供了在不同的错误场景可能有不同类型的错误返回值的灵活性。这也就是 `dyn`,它是 “动态的”(“dynamic”)的缩写。
|
||||
|
||||
第二个改变是去掉了 `expect` 调用并替换为第九章讲到的 `?`。不同于遇到错误就 `panic!`,`?` 会从函数中返回错误值并让调用者来处理它。
|
||||
|
||||
@ -434,8 +434,8 @@ fn main() {
|
||||
|
||||
<span class="caption">示例 12-14:将 `minigrep` crate 引入 *src/main.rs* 的作用域中</span>
|
||||
|
||||
为了将库 crate 引入二进制 crate,我们使用 `extern crate minigrep`。接着增加 `use minigrep::Config` 将 `Config` 类型引入作用域,并使用 crate 名作为 `run` 函数的前缀。通过这些重构,所有功能应该能够联系在一起并运行了。运行 `cargo run` 来确保一切都正确的衔接在一起。
|
||||
为了将库 crate 引入二进制 crate,我们使用了 `use minigrep`。接着 `use minigrep::Config` 将 `Config` 类型引入作用域,并使用 crate 名称作为 `run` 函数的前缀。通过这些重构,所有功能应该能够联系在一起并运行了。运行 `cargo run` 来确保一切都正确的衔接在一起。
|
||||
|
||||
哇哦!这可有很多的工作,不过我们为将来的成功打下了基础。现在处理错误将更容易,同时代码也更加模块化。从现在开始几乎所有的工作都将在 *src/lib.rs* 中进行。
|
||||
|
||||
让我们利用这些新创建的模块的优势来进行一些在旧代码中难以展开的工作,他们在新代码中却很简单:编写测试!
|
||||
让我们利用这些新创建的模块的优势来进行一些在旧代码中难以展开的工作,这些工作在新代码中非常容易实现,那就是:编写测试!
|
||||
|
@ -1,4 +1,4 @@
|
||||
## 采用测试驱动开发完善库的功能
|
||||
## 采用测试驱动开发完善库的功能
|
||||
|
||||
> [ch12-04-testing-the-librarys-functionality.md](https://github.com/rust-lang/book/blob/master/src/ch12-04-testing-the-librarys-functionality.md)
|
||||
> <br>
|
||||
|
@ -1,10 +1,10 @@
|
||||
## 处理环境变量
|
||||
## 处理环境变量
|
||||
|
||||
> [ch12-05-working-with-environment-variables.md](https://github.com/rust-lang/book/blob/master/src/ch12-05-working-with-environment-variables.md)
|
||||
> <br>
|
||||
> commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f
|
||||
|
||||
我们将增加一个额外的功能来改进 `minigrep`:一个通过环境变量启用的大小写不敏感搜索的选项。可以将其设计为一个命令行参数并要求用户每次需要时都加上它,不过相反我们将使用环境变量。这允许用户设置环境变量一次之后在整个终端会话中所有的搜索都将是大小写不敏感的。
|
||||
我们将增加一个额外的功能来改进 `minigrep`:用户可以通过设置环境变量来设置搜索是否是大小写敏感的 。当然,我们也可以将其设计为一个命令行参数并要求用户每次需要时都加上它,不过在这里我们将使用环境变量。这允许用户设置环境变量一次之后在整个终端会话中所有的搜索都将是大小写不敏感的。
|
||||
|
||||
### 编写一个大小写不敏感 `search` 函数的失败测试
|
||||
|
||||
@ -199,7 +199,7 @@ How dreary to be somebody!
|
||||
|
||||
看起来程序仍然能够工作!现在将 `CASE_INSENSITIVE` 设置为 `1` 并仍使用相同的查询 `to`。
|
||||
|
||||
如果你使用 PowerShell,则需要用两句命令而不是一句来设置环境变量并运行程序:
|
||||
如果你使用 PowerShell,则需要用两个命令来设置环境变量并运行程序:
|
||||
|
||||
```text
|
||||
$ $env:CASE_INSENSITIVE=1
|
||||
|
@ -1,4 +1,4 @@
|
||||
## 将错误信息输出到标准错误而不是标准输出
|
||||
## 将错误信息输出到标准错误而不是标准输出
|
||||
|
||||
> [ch12-06-writing-to-stderr-instead-of-stdout.md](https://github.com/rust-lang/book/blob/master/src/ch12-06-writing-to-stderr-instead-of-stdout.md)
|
||||
> <br>
|
||||
@ -10,11 +10,11 @@
|
||||
|
||||
### 检查错误应该写入何处
|
||||
|
||||
首先,让我们观察一下目前 `minigrep` 打印的所有内容都被写入了标准输出,包括应该被写入标准错误的错误信息。可以通过将标准输出流重定向到一个文件同时有意产生一个错误来做到这一点。我们没有重定向标准错误流,所以任何发送到标准错误的内容将会继续显示在屏幕上。
|
||||
首先,让我们观察一下目前 `minigrep` 打印的所有内容是如何被写入标准输出的,包括那些应该被写入标准错误的错误信息。可以通过将标准输出流重定向到一个文件同时有意产生一个错误来做到这一点。我们没有重定向标准错误流,所以任何发送到标准错误的内容将会继续显示在屏幕上。
|
||||
|
||||
命令行程序被期望将错误信息发送到标准错误流,这样即便选择将标准输出流重定向到文件中时仍然能看到错误信息。目前我们的程序并不符合期望;相反我们将看到它将错误信息输出保存到了文件中。
|
||||
|
||||
展示这种行为的方式是通过 `>` 和文件名 *output.txt* 来与运行程序,这个文件是期望重定向标准输出流的位置。并不传递任何参数应该会产生一个错误:
|
||||
我们通过 `>` 和文件名 *output.txt* 来运行程序,我们期望重定向标准输出流到该文件中。在这里,我们没有传递任何参数,所以会产生一个错误:
|
||||
|
||||
```text
|
||||
$ cargo run > output.txt
|
||||
@ -26,7 +26,7 @@ $ cargo run > output.txt
|
||||
Problem parsing arguments: not enough arguments
|
||||
```
|
||||
|
||||
是的,错误信息被打印到了标准输出中。像这样的错误信息被打印到标准错误中将有用的多,并在重定向标准输出时只将成功运行的信息写入文件。我们将改变他们。
|
||||
是的,错误信息被打印到了标准输出中。像这样的错误信息被打印到标准错误中将会有用的多,并且只将成功运行的信息写入文件。接下来我们将对程序进行修改从而以这种方式进行输出。
|
||||
|
||||
### 将错误打印到标准错误
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user