update to ch07-05

This commit is contained in:
KaiserY 2022-02-07 15:06:23 +08:00
parent f1b94ab927
commit 4b0a9c80b2
10 changed files with 84 additions and 294 deletions

View File

@ -5,9 +5,9 @@ mod front_of_house {
}
pub fn eat_at_restaurant() {
// Absolute path
// 绝对路径
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
// 相对路径
front_of_house::hosting::add_to_waitlist();
}

View File

@ -5,9 +5,9 @@ mod front_of_house {
}
pub fn eat_at_restaurant() {
// Absolute path
// 绝对路径
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
// 相对路径
front_of_house::hosting::add_to_waitlist();
}

View File

@ -5,9 +5,9 @@ mod front_of_house {
}
pub fn eat_at_restaurant() {
// Absolute path
// 绝对路径
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
// 相对路径
front_of_house::hosting::add_to_waitlist();
}

View File

@ -15,13 +15,13 @@ mod back_of_house {
}
pub fn eat_at_restaurant() {
// Order a breakfast in the summer with Rye toast
// 在夏天订购一个黑麦土司作为早餐
let mut meal = back_of_house::Breakfast::summer("Rye");
// Change our mind about what bread we'd like
// 改变注意更换想要面包的类型
meal.toast = String::from("Wheat");
println!("I'd like {} toast please", meal.toast);
// The next line won't compile if we uncomment it; we're not allowed
// to see or modify the seasonal fruit that comes with the meal
// 如果取消下一行的注释代码不能编译;
// 不允许查看或修改早餐附带的季节水果
// meal.seasonal_fruit = String::from("blueberries");
}

View File

@ -2,11 +2,11 @@
> [ch07-00-managing-growing-projects-with-packages-crates-and-modules.md](https://github.com/rust-lang/book/blob/main/src/ch07-00-managing-growing-projects-with-packages-crates-and-modules.md)
> <br>
> commit 879fef2345bf32751a83a9e779e0cb84e79b6d3d
> commit 5bd82160c11a90d6d46fc37d7f3ff3e33d120763
当你编写大型程序时,组织你的代码显得尤为重要,因为你想在脑海中通晓整个程序,那几乎是不可能完成的。通过对相关功能进行分组和划分不同功能的代码,你可以清楚在哪里可以找到实现了特定功能的代码,以及在哪里可以改变一个功能的工作方式。
到目前为止,我们编写的程序都在一个文件的一个模块中。伴随着项目的增长,你可以通过将代码分解为多个模块和多个文件来组织代码。一个包可以包含多个二进制 crate 项和一个可选的 crate 库。伴随着包的增长,你可以将包中的部分代码提取出来,做成独立的 crate这些 crate 则作为外部依赖项。本章将会涵盖所有这些概念。对于一个由一系列相互关联的包组合而成的超大型项目Cargo 提供了 “工作空间” 这一功能,我们将在第十四章的 “[Cargo Workspaces](ch14-03-cargo-workspaces.html)” 对此进行讲解。
到目前为止,我们编写的程序都在一个文件的一个模块中。伴随着项目的增长,你可以通过将代码分解为多个模块和多个文件来组织代码。一个包可以包含多个二进制 crate 项和一个可选的 crate 库。伴随着包的增长,你可以将包中的部分代码提取出来,做成独立的 crate这些 crate 则作为外部依赖项。本章将会涵盖所有这些概念。对于一个由一系列相互关联的包组合而成的超大型项目Cargo 提供了 “工作空间” 这一功能,我们将在第十四章的 [“Cargo Workspaces”][workspaces] 对此进行讲解。
除了对功能进行分组以外,封装实现细节可以使你更高级地重用代码:你实现了一个操作后,其他的代码可以通过该代码的公共接口来进行调用,而不需要知道它是如何实现的。你在编写代码时可以定义哪些部分是其他代码可以使用的公共部分,以及哪些部分是你有权更改实现细节的私有部分。这是另一种减少你在脑海中记住项目内容数量的方法。
@ -20,3 +20,5 @@ Rust 有许多功能可以让你管理代码的组织,包括哪些内容可以
* **路径***path*):一个命名例如结构体、函数或模块等项的方式
本章将会涵盖所有这些概念,讨论它们如何交互,并说明如何使用它们来管理作用域。到最后,你会对模块系统有深入的了解,并且能够像专业人士一样使用作用域!
[workspaces]: ch14-03-cargo-workspaces.html

View File

@ -2,15 +2,15 @@
> [ch07-01-packages-and-crates.md](https://github.com/rust-lang/book/blob/main/src/ch07-01-packages-and-crates.md)
> <br>
> commit 879fef2345bf32751a83a9e779e0cb84e79b6d3d
> commit 53f1492a626501ea6fea6c4919a69bdb736b7dcb
模块系统的第一部分,我们将介绍包和 crate。crate 是一个二进制项或者库。*crate root* 是一个源文件Rust 编译器以它为起始点,并构成你的 crate 的根模块(我们将在 “[定义模块来控制作用域与私有性](https://github.com/rust-lang/book/blob/master/src/ch07-02-defining-modules-to-control-scope-and-privacy.md)” 一节深入解读)。*包**package* 是提供一系列功能的一个或者多个 crate。一个包会包含有一个 *Cargo.toml* 文件,阐述如何去构建这些 crate。
模块系统的第一部分,我们将介绍包和 crate。crate 是一个二进制项或者库。*crate root* 是一个源文件Rust 编译器以它为起始点,并构成你的 crate 的根模块(我们将在 [“定义模块来控制作用域与私有性”][modules] 一节深入解读)。*包**package* 是提供一系列功能的一个或者多个 crate。一个包会包含有一个 *Cargo.toml* 文件,阐述如何去构建这些 crate。
包中所包含的内容由几条规则来确立。一个包中至多 **只能** 包含一个库 crate(library crate);包中可以包含任意多个二进制 crate(binary crate);包中至少包含一个 crate无论是库的还是二进制的
包中所包含的内容由几条规则来确立。包中可以包含至多一个库 crate(library crate)。包中可以包含任意多个二进制 crate(binary crate),但是必须至少包含一个 crate无论是库的还是二进制的
让我们来看看创建包的时候会发生什么。首先,我们输入命令 `cargo new`
```text
```console
$ cargo new my-project
Created binary (application) `my-project` package
$ ls my-project
@ -22,10 +22,13 @@ main.rs
当我们输入了这条命令Cargo 会给我们的包创建一个 *Cargo.toml* 文件。查看 *Cargo.toml* 的内容,会发现并没有提到 *src/main.rs*,因为 Cargo 遵循的一个约定:*src/main.rs* 就是一个与包同名的二进制 crate 的 crate 根。同样的Cargo 知道如果包目录中包含 *src/lib.rs*,则包带有与其同名的库 crate*src/lib.rs* 是 crate 根。crate 根文件将由 Cargo 传递给 `rustc` 来实际构建库或者二进制项目。
在此,我们有了一个只包含 *src/main.rs* 的包,意味着它只含有一个名为 `my-project` 的二进制 crate。如果一个包同时含有 *src/main.rs**src/lib.rs*,则它有两个 crate一个库和一个二进制项,且名字都与包相同。通过将文件放在 *src/bin* 目录下,一个包可以拥有多个二进制 crate每个 *src/bin* 下的文件都会被编译成一个独立的二进制 crate。
在此,我们有了一个只包含 *src/main.rs* 的包,意味着它只含有一个名为 `my-project` 的二进制 crate。如果一个包同时含有 *src/main.rs**src/lib.rs*,则它有两个 crate一个二进制的和一个库的,且名字都与包相同。通过将文件放在 *src/bin* 目录下,一个包可以拥有多个二进制 crate每个 *src/bin* 下的文件都会被编译成一个独立的二进制 crate。
一个 crate 会将一个作用域内的相关功能分组到一起,使得该功能可以很方便地在多个项目之间共享。举一个例子,我们在 [第二章](https://github.com/rust-lang/book/blob/master/src/ch02-00-guessing-game-tutorial.md#generating-a-random-number) 使用的 `rand` crate 提供了生成随机数的功能。通过将 `rand` crate 加入到我们项目的作用域中,我们就可以在自己的项目中使用该功能。`rand` crate 提供的所有功能都可以通过该 crate 的名字:`rand` 进行访问。
一个 crate 会将一个作用域内的相关功能分组到一起,使得该功能可以很方便地在多个项目之间共享。举一个例子,我们在 [第二章][rand] 使用的 `rand` crate 提供了生成随机数的功能。通过将 `rand` crate 加入到我们项目的作用域中,我们就可以在自己的项目中使用该功能。`rand` crate 提供的所有功能都可以通过该 crate 的名字:`rand` 进行访问。
将一个 crate 的功能保持在其自身的作用域中,可以知晓一些特定的功能是在我们的 crate 中定义的还是在 `rand` crate 中定义的,这可以防止潜在的冲突。例如,`rand` crate 提供了一个名为 `Rng` 的特性trait。我们还可以在我们自己的 crate 中定义一个名为 `Rng``struct`。因为一个 crate 的功能是在自身的作用域进行命名的,当我们将 `rand` 作为一个依赖,编译器不会混淆 `Rng` 这个名字的指向。在我们的 crate 中,它指向的是我们自己定义的 `struct Rng`。我们可以通过 `rand::Rng` 这一方式来访问 `rand` crate 中的 `Rng` 特性trait
接下来让我们来说一说模块系统!
[modules]: ch07-02-defining-modules-to-control-scope-and-privacy.html
[rand]: ch02-00-guessing-game-tutorial.html#生成一个随机数

View File

@ -2,7 +2,7 @@
> [ch07-02-defining-modules-to-control-scope-and-privacy.md](https://github.com/rust-lang/book/blob/main/src/ch07-02-defining-modules-to-control-scope-and-privacy.md)
> <br>
> commit 34b089627cca09a73ce92a052222304bff0056e3
> commit eb60fedc9ccd72999f9aabd82f5936ca0143dd8f
在本节,我们将讨论模块和其它一些关于模块系统的部分,如允许你命名项的 *路径**paths*);用来将路径引入作用域的 `use` 关键字;以及使项变为公有的 `pub` 关键字。我们还将讨论 `as` 关键字、外部包和 glob 运算符。现在,让我们把注意力放在模块上!
@ -14,22 +14,8 @@
<span class="filename">文件名: src/lib.rs</span>
```rust
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
fn seat_at_table() {}
}
mod serving {
fn take_order() {}
fn server_order() {}
fn take_payment() {}
}
}
```rust,noplayground
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-01/src/lib.rs}}
```
<span class="caption">示例 7-1一个包含了其他内置了函数的模块的 `front_of_house` 模块</span>

View File

@ -1,36 +1,23 @@
## 路径用于引用模块树中的项
> [ch07-03-paths-for-referring-to-an-item-in-the-module-tree.md](https://github.com/rust-lang/book/blob/main/src/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.md)
> <br>
> commit cc6a1ef2614aa94003566027b285b249ccf961fa
> [ch07-03-paths-for-referring-to-an-item-in-the-module-tree.md](https://github.com/rust-lang/book/blob/main/src/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.md) > <br>
> commit 9c0fa2714859738ff73cbbb829592e4c037d7e46
来看一下 Rust 如何在模块树中找到一个项的位置,我们使用路径的方式,就像在文件系统使用路径一样。如果我们想要调用一个函数,我们需要知道它的路径。
路径有两种形式:
* **绝对路径***absolute path*)从 crate 根开始,以 crate 名或者字面值 `crate` 开头。
* **相对路径***relative path*)从当前模块开始,以 `self`、`super` 或当前模块的标识符开头。
- **绝对路径**_absolute path_)从 crate 根开始,以 crate 名或者字面值 `crate` 开头。
- **相对路径**_relative path_)从当前模块开始,以 `self`、`super` 或当前模块的标识符开头。
绝对路径和相对路径都后跟一个或多个由双冒号(`::`)分割的标识符。
让我们回到示例 7-1。我们如何调用 `add_to_waitlist` 函数?还是同样的问题,`add_to_waitlist` 函数的路径是什么?在示例 7-3 中,我们通过删除一些模块和函数,稍微简化了一下我们的代码。我们在 crate 根定义了一个新函数 `eat_at_restaurant`,并在其中展示调用 `add_to_waitlist` 函数的两种方法。`eat_at_restaurant` 函数是我们 crate 库的一个公共API所以我们使用 `pub` 关键字来标记它。在 “[使用`pub`关键字暴露路径](ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#exposing-paths-with-the-pub-keyword)” 一节,我们将详细介绍 `pub`。注意,这个例子无法编译通过,我们稍后会解释原因。
让我们回到示例 7-1。我们如何调用 `add_to_waitlist` 函数?还是同样的问题,`add_to_waitlist` 函数的路径是什么?在示例 7-3 中,我们通过删除一些模块和函数,稍微简化了一下我们的代码。我们在 crate 根定义了一个新函数 `eat_at_restaurant`,并在其中展示调用 `add_to_waitlist` 函数的两种方法。`eat_at_restaurant` 函数是我们 crate 库的一个公共 API所以我们使用 `pub` 关键字来标记它。在 [“使用`pub`关键字暴露路径”][pub] 一节,我们将详细介绍 `pub`。注意,这个例子无法编译通过,我们稍后会解释原因。
<span class="filename">文件名: src/lib.rs</span>
```rust,ignore,does_not_compile
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
front_of_house::hosting::add_to_waitlist();
}
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-03/src/lib.rs}}
```
<span class="caption">示例 7-3: 使用绝对路径和相对路径来调用 `add_to_waitlist` 函数</span>
@ -45,27 +32,15 @@ pub fn eat_at_restaurant() {
让我们试着编译一下示例 7-3并查明为何不能编译示例 7-4 展示了这个错误。
```text
$ cargo build
Compiling restaurant v0.1.0 (file:///projects/restaurant)
error[E0603]: module `hosting` is private
--> src/lib.rs:9:28
|
9 | crate::front_of_house::hosting::add_to_waitlist();
| ^^^^^^^
error[E0603]: module `hosting` is private
--> src/lib.rs:12:21
|
12 | front_of_house::hosting::add_to_waitlist();
| ^^^^^^^
```console
{{#include ../listings/ch07-managing-growing-projects/listing-07-03/output.txt}}
```
<span class="caption">示例 7-4: 构建示例 7-3 出现的编译器错误</span>
错误信息说 `hosting` 模块是私有的。换句话说,我们拥有 `hosting` 模块和 `add_to_waitlist` 函数的的正确路径,但是 Rust 不让我们使用,因为它不能访问私有片段。
模块不仅对于你组织代码很有用。他们还定义了 Rust 的 *私有性边界**privacy boundary*):这条界线不允许外部代码了解、调用和依赖被封装的实现细节。所以,如果你希望创建一个私有函数或结构体,你可以将其放入模块。
模块不仅对于你组织代码很有用。他们还定义了 Rust 的 _私有性边界__privacy boundary_这条界线不允许外部代码了解、调用和依赖被封装的实现细节。所以如果你希望创建一个私有函数或结构体你可以将其放入模块。
Rust 中默认所有项(函数、方法、结构体、枚举、模块和常量)都是私有的。父模块中的项不能使用子模块中的私有项,但是子模块中的项可以使用他们父模块中的项。这是因为子模块封装并隐藏了他们的实现详情,但是子模块可以看到他们定义的上下文。继续拿餐馆作比喻,把私有性规则想象成餐馆的后台办公室:餐馆内的事务对餐厅顾客来说是不可知的,但办公室经理可以洞悉其经营的餐厅并在其中做任何事情。
@ -78,44 +53,20 @@ Rust 选择以这种方式来实现模块系统功能,因此默认隐藏内部
<span class="filename">文件名: src/lib.rs</span>
```rust,ignore,does_not_compile
mod front_of_house {
pub mod hosting {
fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
front_of_house::hosting::add_to_waitlist();
}
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-05/src/lib.rs}}
```
<span class="caption">示例 7-5: 使用 `pub` 关键字声明 `hosting` 模块使其可在 `eat_at_restaurant` 使用</span>
不幸的是,示例 7-5 的代码编译仍然有错误,如示例 7-6 所示。
```text
$ cargo build
Compiling restaurant v0.1.0 (file:///projects/restaurant)
error[E0603]: function `add_to_waitlist` is private
--> src/lib.rs:9:37
|
9 | crate::front_of_house::hosting::add_to_waitlist();
| ^^^^^^^^^^^^^^^
error[E0603]: function `add_to_waitlist` is private
--> src/lib.rs:12:30
|
12 | front_of_house::hosting::add_to_waitlist();
| ^^^^^^^^^^^^^^^
```console
{{#include ../listings/ch07-managing-growing-projects/listing-07-05/output.txt}}
```
<span class="caption">示例 7-6: 构建示例 7-5 出现的编译器错误</span>
发生了什么?在 `mod hosting` 前添加了 `pub` 关键字,使其变成公有的。伴随着这种变化,如果我们可以访问 `front_of_house`,那我们也可以访问 `hosting`。但是 `hosting`*内容**contents* 仍然是私有的;这表明使模块公有并不使其内容也是公有的。模块上的 `pub` 关键字只允许其父模块引用它。
发生了什么?在 `mod hosting` 前添加了 `pub` 关键字,使其变成公有的。伴随着这种变化,如果我们可以访问 `front_of_house`,那我们也可以访问 `hosting`。但是 `hosting`_内容__contents_ 仍然是私有的;这表明使模块公有并不使其内容也是公有的。模块上的 `pub` 关键字只允许其父模块引用它。
示例 7-6 中的错误说,`add_to_waitlist` 函数是私有的。私有性规则不但应用于模块,还应用于结构体、枚举、函数和方法。
@ -123,21 +74,8 @@ error[E0603]: function `add_to_waitlist` is private
<span class="filename">文件名: src/lib.rs</span>
```rust
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
front_of_house::hosting::add_to_waitlist();
}
# fn main() {}
```rust,noplayground,test_harness
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-07/src/lib.rs}}
```
<span class="caption">示例 7-7: 为 `mod hosting`
@ -158,18 +96,8 @@ pub fn eat_at_restaurant() {
<span class="filename">文件名: src/lib.rs</span>
```rust
fn serve_order() {}
mod back_of_house {
fn fix_incorrect_order() {
cook_order();
super::serve_order();
}
fn cook_order() {}
}
# fn main() {}
```rust,noplayground,test_harness
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-08/src/lib.rs}}
```
<span class="caption">示例 7-8: 使用以 `super` 开头的相对路径从父目录开始调用函数</span>
@ -182,34 +110,8 @@ mod back_of_house {
<span class="filename">文件名: src/lib.rs</span>
```rust
mod back_of_house {
pub struct Breakfast {
pub toast: String,
seasonal_fruit: String,
}
impl Breakfast {
pub fn summer(toast: &str) -> Breakfast {
Breakfast {
toast: String::from(toast),
seasonal_fruit: String::from("peaches"),
}
}
}
}
pub fn eat_at_restaurant() {
// Order a breakfast in the summer with Rye toast
let mut meal = back_of_house::Breakfast::summer("Rye");
// Change our mind about what bread we'd like
meal.toast = String::from("Wheat");
println!("I'd like {} toast please", meal.toast);
// The next line won't compile if we uncomment it; we're not allowed
// to see or modify the seasonal fruit that comes with the meal
// meal.seasonal_fruit = String::from("blueberries");
}
```rust,noplayground
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-09/src/lib.rs}}
```
<span class="caption">示例 7-9: 带有公有和私有字段的结构体</span>
@ -222,18 +124,8 @@ pub fn eat_at_restaurant() {
<span class="filename">文件名: src/lib.rs</span>
```rust
mod back_of_house {
pub enum Appetizer {
Soup,
Salad,
}
}
pub fn eat_at_restaurant() {
let order1 = back_of_house::Appetizer::Soup;
let order2 = back_of_house::Appetizer::Salad;
}
```rust,noplayground
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-10/src/lib.rs}}
```
<span class="caption">示例 7-10: 设计公有枚举,使其所有成员公有</span>
@ -241,3 +133,5 @@ pub fn eat_at_restaurant() {
因为我们创建了名为 `Appetizer` 的公有枚举,所以我们可以在 `eat_at_restaurant` 中使用 `Soup``Salad` 成员。如果枚举成员不是公有的,那么枚举会显得用处不大;给枚举的所有成员挨个添加 `pub` 是很令人恼火的,因此枚举成员默认就是公有的。结构体通常使用时,不必将它们的字段公有化,因此结构体遵循常规,内容全部是私有的,除非使用 `pub` 关键字。
还有一种使用 `pub` 的场景我们还没有涉及到,那就是我们最后要讲的模块功能:`use` 关键字。我们将先单独介绍 `use`,然后展示如何结合使用 `pub``use`
[pub]: ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#使用-pub-关键字暴露路径

View File

@ -2,7 +2,7 @@
> [ch07-04-bringing-paths-into-scope-with-the-use-keyword.md](https://github.com/rust-lang/book/blob/main/src/ch07-04-bringing-paths-into-scope-with-the-use-keyword.md)
> <br>
> commit 6d3e76820418f2d2bb203233c61d90390b5690f1
> commit 2d605f66b3d891dea0a2f684ece508aa2282b854
到目前为止,似乎我们编写的用于调用函数的路径都很冗长且重复,并不方便。例如,示例 7-7 中,无论我们选择 `add_to_waitlist` 函数的绝对路径还是相对路径,每次我们想要调用 `add_to_waitlist` 时,都必须指定`front_of_house` 和 `hosting`。幸运的是,有一种方法可以简化这个过程。我们可以使用 `use` 关键字将路径一次性引入作用域,然后调用该路径中的项,就如同它们是本地项一样。
@ -10,21 +10,8 @@
<span class="filename">文件名: src/lib.rs</span>
```rust
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
# fn main() {}
```rust,noplayground,test_harness
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-11/src/lib.rs}}
```
<span class="caption">示例 7-11: 使用 `use` 将模块引入作用域</span>
@ -35,21 +22,8 @@ pub fn eat_at_restaurant() {
<span class="filename">文件名: src/lib.rs</span>
```rust
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
# fn main() {}
```rust,noplayground,test_harness
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-12/src/lib.rs}}
```
<span class="caption">示例 7-12: 使用 `use` 和相对路径将模块引入作用域</span>
@ -60,21 +34,8 @@ pub fn eat_at_restaurant() {
<span class="filename">文件名: src/lib.rs</span>
```rust
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting::add_to_waitlist;
pub fn eat_at_restaurant() {
add_to_waitlist();
add_to_waitlist();
add_to_waitlist();
}
# fn main() {}
```rust,noplayground,test_harness
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-13/src/lib.rs}}
```
<span class="caption">示例 7-13: 使用 `use``add_to_waitlist` 函数引入作用域,这并不符合习惯</span>
@ -86,12 +47,7 @@ pub fn eat_at_restaurant() {
<span class="filename">文件名: src/main.rs</span>
```rust
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert(1, 2);
}
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-14/src/main.rs}}
```
<span class="caption">示例 7-14: 将 `HashMap` 引入作用域的习惯用法</span>
@ -102,19 +58,8 @@ fn main() {
<span class="filename">文件名: src/lib.rs</span>
```rust
use std::fmt;
use std::io;
fn function1() -> fmt::Result {
// --snip--
# Ok(())
}
fn function2() -> io::Result<()> {
// --snip--
# Ok(())
}
```rust,noplayground
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-15/src/lib.rs:here}}
```
<span class="caption">示例 7-15: 使用父模块将两个具有相同名称的类型引入同一作用域</span>
@ -127,19 +72,8 @@ fn function2() -> io::Result<()> {
<span class="filename">文件名: src/lib.rs</span>
```rust
use std::fmt::Result;
use std::io::Result as IoResult;
fn function1() -> Result {
// --snip--
# Ok(())
}
fn function2() -> IoResult<()> {
// --snip--
# Ok(())
}
```rust,noplayground
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-16/src/lib.rs:here}}
```
<span class="caption">示例 7-16: 使用 `as` 关键字重命名引入作用域的类型</span>
@ -154,21 +88,8 @@ fn function2() -> IoResult<()> {
<span class="filename">文件名: src/lib.rs</span>
```rust
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
# fn main() {}
```rust,noplayground,test_harness
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-17/src/lib.rs}}
```
<span class="caption">示例 7-17: 通过 `pub use` 使名称可引入任何代码的作用域中</span>
@ -184,8 +105,7 @@ pub fn eat_at_restaurant() {
<span class="filename">文件名: Cargo.toml</span>
```toml
[dependencies]
rand = "0.5.5"
{{#include ../listings/ch02-guessing-game-tutorial/listing-02-02/Cargo.toml:9:}}
```
*Cargo.toml* 中加入 `rand` 依赖告诉了 Cargo 要从 [crates.io](https://crates.io) 下载 `rand` 和其依赖,并使其可在项目代码中使用。
@ -193,11 +113,7 @@ rand = "0.5.5"
接着,为了将 `rand` 定义引入项目包的作用域,我们加入一行 `use` 起始的包名,它以 `rand` 包名开头并列出了需要引入作用域的项。回忆一下第二章的 “生成一个随机数” 部分,我们曾将 `Rng` trait 引入作用域并调用了 `rand::thread_rng` 函数:
```rust,ignore
use rand::Rng;
fn main() {
let secret_number = rand::thread_rng().gen_range(1, 101);
}
{{#rustdoc_include ../listings/ch02-guessing-game-tutorial/listing-02-03/src/main.rs:ch07-04}}
```
[crates.io](https://crates.io) 上有很多 Rust 社区成员发布的包,将其引入你自己的项目都需要一道相同的步骤:在 *Cargo.toml* 列出它们并通过 `use` 将其中定义的项引入项目包的作用域中。
@ -216,19 +132,16 @@ use std::collections::HashMap;
<span class="filename">文件名: src/main.rs</span>
```rust
use std::cmp::Ordering;
use std::io;
// ---snip---
```rust,ignore
{{#rustdoc_include ../listings/ch07-managing-growing-projects/no-listing-01-use-std-unnested/src/main.rs:here}}
```
相反,我们可以使用嵌套路径将相同的项在一行中引入作用域。这么做需要指定路径的相同部分,接着是两个冒号,接着是大括号中的各自不同的路径部分,如示例 7-18 所示。
<span class="filename">文件名: src/main.rs</span>
```rust
use std::{cmp::Ordering, io};
// ---snip---
```rust,ignore
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-18/src/main.rs:here}}
```
<span class="caption">示例 7-18: 指定嵌套的路径在一行中将多个带有相同前缀的项引入作用域</span>
@ -239,9 +152,8 @@ use std::{cmp::Ordering, io};
<span class="filename">文件名: src/lib.rs</span>
```rust
use std::io;
use std::io::Write;
```rust,noplayground
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-19/src/lib.rs}}
```
<span class="caption">示例 7-19: 通过两行 `use` 语句引入两个路径,其中一个是另一个的子路径</span>
@ -250,8 +162,8 @@ use std::io::Write;
<span class="filename">文件名: src/lib.rs</span>
```rust
use std::io::{self, Write};
```rust,noplayground
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-20/src/lib.rs}}
```
<span class="caption">示例 7-20: 将示例 7-19 中部分重复的路径合并为一个 `use` 语句</span>
@ -269,3 +181,6 @@ use std::collections::*;
这个 `use` 语句将 `std::collections` 中定义的所有公有项引入当前作用域。使用 glob 运算符时请多加小心Glob 会使得我们难以推导作用域中有什么名称和它们是在何处定义的。
glob 运算符经常用于测试模块 `tests` 中,这时会将所有内容引入作用域;我们将在第十一章 “如何编写测试” 部分讲解。glob 运算符有时也用于 prelude 模式;查看 [标准库中的文档](https://doc.rust-lang.org/std/prelude/index.html#other-preludes) 了解这个模式的更多细节。
[rand]: ch02-00-guessing-game-tutorial.html#生成一个随机数
[writing-tests]: ch11-01-writing-tests.html#如何编写测试

View File

@ -2,7 +2,7 @@
> [ch07-05-separating-modules-into-different-files.md](https://github.com/rust-lang/book/blob/main/src/ch07-05-separating-modules-into-different-files.md)
> <br>
> commit a5a5bf9d6ea5763a9110f727911a21da854b1d90
> commit d5584fb1efeaf8aadfc7caf516df7f1ca0820ceb
到目前为止,本章所有的例子都在一个文件中定义多个模块。当模块变得更大时,你可能想要将它们的定义移动到单独的文件中,从而使代码更容易阅读。
@ -11,15 +11,7 @@
<span class="filename">文件名: src/lib.rs</span>
```rust,ignore
mod front_of_house;
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-21-and-22/src/lib.rs}}
```
<span class="caption">示例 7-21: 声明 `front_of_house` 模块,其内容将位于 *src/front_of_house.rs*</span>
@ -28,10 +20,8 @@ pub fn eat_at_restaurant() {
<span class="filename">文件名: src/front_of_house.rs</span>
```rust
pub mod hosting {
pub fn add_to_waitlist() {}
}
```rust,ignore
{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-21-and-22/src/front_of_house.rs}}
```
<span class="caption">示例 7-22: 在 *src/front_of_house.rs* 中定义 `front_of_house`
@ -41,16 +31,16 @@ pub mod hosting {
<span class="filename">文件名: src/front_of_house.rs</span>
```rust
pub mod hosting;
```rust,ignore
{{#rustdoc_include ../listings/ch07-managing-growing-projects/no-listing-02-extracting-hosting/src/front_of_house.rs}}
```
接着我们创建一个 *src/front_of_house* 目录和一个包含 `hosting` 模块定义的 *src/front_of_house/hosting.rs* 文件:
<span class="filename">文件名: src/front_of_house/hosting.rs</span>
```
pub fn add_to_waitlist() {}
```rust
{{#rustdoc_include ../listings/ch07-managing-growing-projects/no-listing-02-extracting-hosting/src/front_of_house/hosting.rs}}
```
模块树依然保持相同,`eat_at_restaurant` 中的函数调用也无需修改继续保持有效,即便其定义存在于不同的文件中。这个技巧让你可以在模块代码增长时,将它们移动到新文件中。