update to ch07-02

pull/270/head
KaiserY 6 years ago
parent cecbf32d79
commit 8ebec19624

@ -36,10 +36,9 @@
## 基本 Rust 技能 ## 基本 Rust 技能
- [模块](ch07-00-modules.md) - [包、crate 与 模块](ch07-00-packages-crates-and-modules.md)
- [`mod` 与文件系统](ch07-01-mod-and-the-filesystem.md) - [包和 crate 用来创建库和二进制项目](ch07-01-packages-and-crates-for-making-libraries-and-executables.md)
- [使用 `pub` 控制可见性](ch07-02-controlling-visibility-with-pub.md) - [模块系统用来控制作用域和私有性](ch07-02-modules-and-use-to-control-scope-and-privacy.md)
- [在不同的模块中引用命名](ch07-03-importing-names-with-use.md)
- [通用集合类型](ch08-00-common-collections.md) - [通用集合类型](ch08-00-common-collections.md)
- [vector](ch08-01-vectors.md) - [vector](ch08-01-vectors.md)

@ -1,15 +0,0 @@
# 使用模块组织和复用代码
> [ch07-00-modules.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch07-00-modules.md)
> <br>
> commit 050ff6f34f107b2c8695807fc16aeb827ffe1fa3
在你刚开始编写 Rust 程序时,代码可能仅仅位于 `main` 函数中。随着代码量的增长为了复用和更好地组织代码最终你会将功能移动到其他函数中。通过将代码拆分成更小的块每一个块就更易于理解。但是如果你有太多的函数该怎么办呢Rust 有一个模块系统,可以有组织地复用代码。
就跟你将代码行提取到一个函数中一样,也可以将函数(和其他代码,例如结构体和枚举)提取到不同模块中。**模块***module*)是一个包含函数或类型定义的命名空间,你可以选择这些定义能(公有)或不能(私有)在其模块外可见。下面是一个模块如何工作的梗概:
* 使用 `mod` 关键字声明新模块。此模块中的代码要么直接位于声明之后的大括号中,要么位于另一个文件。
* 函数、类型、常量和模块默认都是私有的。可以使用 `pub` 关键字将其变成公有并在其命名空间之外可见。
* `use` 关键字将模块或模块中的定义引入到作用域中以便于引用它们。
我们会逐一了解这每一部分并学习如何将它们结合在一起。

@ -0,0 +1,16 @@
# 包、crate 与 模块
> [ch07-00-packages-crates-and-modules.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch07-00-modules.md)
> <br>
> commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f
编写程序时一个核心的问题是 **作用域***scope*):在代码的某处编译器知道哪些变量名?允许调用哪些函数?这些变量引用的又是什么?
Rust 有一系列与作用域相关的功能。这有时被称为 “模块系统”“the module system”不过又不仅仅是模块
* **包***Packages*)是 Cargo 的一个功能,它允许你构建、测试核分享 crate。
* *Crates* 是一个模块的树形结构,它形成了库或二进制项目。
* **模块***Modules*)和 *use* 关键字允许你控制作用域和路径的私有性。
* **路径***path*)是一个命名例如结构体、函数或模块等项的方式
本章将会覆盖所有这些概念。很快我们就能像专家一样将命名引入作用域、定义作用域和将命名导出到作用域!

@ -0,0 +1,31 @@
## 包和 crate 用来创建库和二进制项目
> [ch07-01-mod-and-the-filesystem.md](https://github.com/rust-lang/book/blob/master/src/ch07-01-packages-and-crates-for-making-libraries-and-executables.md)
> <br>
> commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f
让我们聊聊 **模块** 与 *crate*。下面是一个总结:
* *crate* 是一个二进制或库项目。
* **crate 根***crate root*)是一个用来描述如何构建 crate 的文件。
* **包** 带有 *Cargo.toml* 文件用以描述如何构建一个或多个 crate。一个包中至多可以有一个库项目。
所以当运行 `cargo new` 时是在创建一个包:
```text
$ cargo new my-project
Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs
```
因为 Cargo 创建了 *Cargo.toml*,这意味着现在我们有了一个包。如果查看 *Cargo.toml* 的内容,会发现并没有提到 *src/main.rs*。然而Cargo 的约定是如果在代表包的 *Cargo.toml* 的同级目录下包含 *src* 目录且其中包含 *main.rs* 文件的话Cargo 就知道这个包带有一个与包同名的二进制 crate*src/main.rs* 就是 crate 根。另一个约定如果包目录中包含 *src/lib.rs*,则包带有与其同名的库 crate*src/lib.rs* 是 crate 根。crate 根文件将由 Cargo 传递给 `rustc` 来实际构建库或者二进制项目。
一个包可以带有零个或一个库 crate 和任意多个二进制 crate。一个包中必须带有至少一个库或者二进制crate。
如果包同时包含 *src/main.rs**src/lib.rs*,那么它带有两个 crate一个库和一个二进制项目同名。如果只有其中之一则包将只有一个库或者二进制 crate。包可以带有多个二进制 crate需将其文件置于 *src/bin* 目录;每个文件将是一个单独的二进制 crate。
接下来让我们讨论模块!

@ -0,0 +1,503 @@
## 模块系统用来控制作用域和私有性
> [ch07-01-mod-and-the-filesystem.md](https://github.com/rust-lang/book/blob/master/src/ch07-02-modules-and-use-to-control-scope-and-privacy.md)
> <br>
> commit 820ac357f6cf0e866e5a8e7a9c57dd3e17e9f8ca
Rust 的此部分功能通常被引用为 “模块系统”“the module system”不过其包括了一些除模块之外的功能。在本部分我们会讨论
* 模块,一个组织代码和控制路径私有性的方式
* 路径一个命名项item的方式
* `use` 关键字用来将路径引入作用域
* `pub` 关键字使项变为公有
* `as` 关键字用于将项引入作用域时进行重命名
* 使用外部包
* 嵌套路径用来消除大量的 `use` 语句
* 使用 glob 运算符将模块的所有内容引入作用域
* 如何将不同模块分割到单独的文件中
首先讲讲模块。模块允许我们将代码组织起来。示例 7-1 是一个例子,这些代码定义了名为 `sound` 的模块,其包含名为 `guitar` 的函数。
<span class="filename">文件名: src/main.rs</span>
```rust
mod sound {
fn guitar() {
// 函数体
}
}
fn main() {
}
```
<span class="caption">示例 7-1: 包含 `guitar` 函数和 `main` 函数的 `sound` 模块</span>
这里定义了两个函数,`guitar` 和 `main`。`guitar` 函数定义于 `mod` 块中。这个块定义了 `sound` 模块。
为了将代码组织到模块层次体系中,可以将模块嵌套进其他模块,如示例 7-2 所示:
<span class="filename">文件名: src/main.rs</span>
```rust
mod sound {
mod instrument {
mod woodwind {
fn clarinet() {
// 函数体
}
}
}
mod voice {
}
}
fn main() {
}
```
<span class="caption">示例 7-2: 模块中的模块</span>
在这个例子中,我们像示例 7-1 一样定义了 `sound` 模块。接着在 `sound` 模块中定义了 `instrument``voice` 模块。`instrument` 模块中定义了另一个模块 `woodwind`,这个模块包含一个函数 `clarinet`
在 “包和 crate 用来创建库和二进制项目” 部分提到 *src/main.rs**src/lib.rs* 被称为 **crate 根**。他们被称为 crate 根是因为这两个文件在 crate 模块树的根组成了名为 `crate` 模块。所以示例 7-2 中,有如示例 7-3 所示的模块树:
```text
crate
└── sound
└── instrument
└── woodwind
└── voice
```
<span class="caption">示例 7-3: 示例 7-2 中代码的模块树</span>
这个树展示了模块如何嵌套在其他模块中(比如 `woodwind` 嵌套在 `instrument` 中)以及模块如何作为其他模块的子模块的(`instrument` 和 `voice` 都定义在 `sound` 中)。整个模块树都位于名为 `crate` 这个隐式模块的根下。
这个树可能会令你想起电脑上文件系统的目录树;这事一个非常恰当的比喻!就像文件系统的目录,将代码放入任意模块也将创建对应的组织结构体。另一个相似点是为了引用文件系统或模块树中的项,需要使用 **路径***path*)。
### 路径用来引用模块树中的项
如果想要调用函数,需要知道其 **路径**。“路径” 是 “名称”“name” 的同义词,不过它用于文件系统语境。另外,函数、结构体和其他项可能会有多个指向相同项的路径,所以 “名称” 这个概念不太准确。
**路径** 可以有两种形式:
* **绝对路径***absolute path*)从 crate 根开始,以 crate 名或者字面值 `crate` 开头。
* **相对路径***relative path*)从当前模块开始,以 `self`、`super` 或当前模块的标识符开头。
绝对路径和相对路径都后跟一个或多个由双分号(`::`)分割的标识符。
如何在示例 7-2 的 `main` 函数中调用 `clarinet` 函数呢?也就是说,`clarinet` 函数的路径是什么呢?在示例 7-4 中稍微简化了代码,移除了一些模块,并展示了两种在 `main` 中调用 `clarinet` 函数的方式。这个例子还不能编译,我们会解释为什么。
<span class="filename">文件名: src/main.rs</span>
```rust,ignore,does_not_compile
mod sound {
mod instrument {
fn clarinet() {
// 函数体
}
}
}
fn main() {
// 绝对路径
crate::sound::instrument::clarinet();
// Relative path
sound::instrument::clarinet();
}
```
<span class="caption">示例 7-4: 在简化的模块树中,分别使用绝对路径和相对路径在 `main` 中调用 `clarinet` 函数</span>
第一种从 `main` 函数中调用 `clarinet` 函数的方式使用绝对路径。因为 `clarinet``main` 定义于同一 crate 中,我们使用 `crate` 关键字来开始绝对路径。接着包含每一个模块直到 `clarinet`。这类似于指定 `/sound/instrument/clarinet` 来运行电脑上这个位置的程序;使用 `crate` 从 crate 根开始就类似于在 shell 中使用 `/` 从文件系统根开始。
第二种从 `main` 函数中调用 `clarinet` 函数的方式使用相对路径。该路径以 `sound` 开始,它是定义于与 `main` 函数相同模块树级别的模块。这类似于指定 `sound/instrument/clarinet` 来运行电脑上这个位置的程序;以名称开头意味着路径是相对的。
示例 7-4 提到了它并不能编译,让我们尝试编译并看看为什么不行!示例 7-5 展示了错误。
```text
$ cargo build
Compiling sampleproject v0.1.0 (file:///projects/sampleproject)
error[E0603]: module `instrument` is private
--> src/main.rs:11:19
|
11 | crate::sound::instrument::clarinet();
| ^^^^^^^^^^
error[E0603]: module `instrument` is private
--> src/main.rs:14:12
|
14 | sound::instrument::clarinet();
| ^^^^^^^^^^
```
<span class="caption">示例 7-5: 构建示例 7-4 出现的编译器错误</span>
错误信息说 `instrument` 模块是私有的。可以看到 `instrument` 模块和 `clarinet` 函数的路径是正确的,不过 Rust 不让我们使用,因为他们是私有的。现在是学习 `pub` 关键字的时候了!
### 模块作为私有性的边界
之前我们讨论到模块的语法和组织代码的用途。Rust 采用模块还有另一个原因:模块是 Rust 中的 **私有性边界***privacy boundary*)。如果你希望函数或结构体是私有的,将其放入模块。私有性规则有如下:
* 所有项(函数、方法、结构体、枚举、模块和常量)默认是私有的。
* 可以使用 `pub` 关键字使项变为共有。
* 不允许使用定义于当前模块的子模块中的私有代码。
* 允许使用任何定义于父模块或当前模块中的代码。
换句话说,对于没有 `pub` 关键字的项,当你从当前模块向 “下” 看时是私有的,不过当你向 “上” 看时是公有的。再一次想象一下文件系统:如果你没有某个目录的权限,则无法从父目录中查看其内容。如果有该目录的权限,则可以查看其中的目录和任何父目录。
### 使用 `pub` 关键字使项变为公有
示例 7-5 中的错误说 `instrument` 模块使私有的。让我们使用 `pub` 关键字标记 `instrument` 模块使其可以在 `main` 函数中使用。这些改变如示例 7-6 所示,它仍然不能编译,不过会产生一个不同的错误:
<span class="filename">文件名: src/main.rs</span>
```rust,ignore,does_not_compile
mod sound {
pub mod instrument {
fn clarinet() {
// 函数体
}
}
}
fn main() {
// Absolute path
crate::sound::instrument::clarinet();
// Relative path
sound::instrument::clarinet();
}
```
<span class="caption">示例 7-6: 将 `instrument` 模块声明为 `pub` 以便可以在 `main` 中使用</span>
`mod instrument` 之前增加 `pub` 关键字使得模块变为公有。通过这个改变如果允许访问 `sound` 的话,我们就可以访问 `instrument`。`instrument` 的内容仍然是私有的;使得模块公有并不使其内容也是公有的。模块上的 `pub` 关键字允许其父模块引用它。
不过示例 7-6 中的代码仍然产生错误,如示例 7-7 所示:
```text
$ cargo build
Compiling sampleproject v0.1.0 (file:///projects/sampleproject)
error[E0603]: function `clarinet` is private
--> src/main.rs:11:31
|
11 | crate::sound::instrument::clarinet();
| ^^^^^^^^
error[E0603]: function `clarinet` is private
--> src/main.rs:14:24
|
14 | sound::instrument::clarinet();
| ^^^^^^^^
```
<span class="caption">示例 7-7: 构建示例 7-6 时产生的编译器错误</span>
现在的错误表明 `clarinet` 函数是私有的。私有性规则适用于结构体、枚举、函数和方法以及模块。
`clarinet` 函数前增加 `pub` 关键字使其变为公有,如示例 7-8 所示:
<span class="filename">文件名: src/main.rs</span>
```rust
mod sound {
pub mod instrument {
pub fn clarinet() {
// 函数体
}
}
}
fn main() {
// 绝对路径
crate::sound::instrument::clarinet();
// 相对路径
sound::instrument::clarinet();
}
```
<span class="caption">示例 7-8: 在 `mod
instrument` 和 `fn clarinet` 之前都增加 `pub` 关键字使我们可以在 `main` 中调用此函数</span>
现在可以编译了!让我们看看绝对路径和相对路径再次检查为什么增加 `pub` 关键字使得我们可以在 `main` 中调用这些路径。
在绝对路径的情况下,我们从 `crate`,也就是 crate 根开始。从这开始有 `sound`,这是一个定义于 crate 根中的模块。`sound` 模块不是公有的,不过因为 `main` 函数与 `sound` 定义于同一模块中,可以从 `main` 中引用 `sound`。接下来是 `instrument`,这个模块标记为 `pub`。我们可以访问 `instrument` 的父模块,所以可以访问 `instrument`。最后,`clarinet` 函数被标记为 `pub` 所以可以访问其父模块,所以这个函数调用是有效的!
在相对路径的情况下,其逻辑与绝对路径相同,除了第一步。不同于从 crate 根开始,路径从 `sound` 开始。`sound` 模块与 `main` 定义于同一模块,所以从 `main` 所在模块开始定义的路径是有效的。接下来因为 `instrument``clarinet` 被标记为 `pub`,路径其余的部分也是有效的,因此函数调用也是有效的!
### 使用 `super` 开始相对路径
也可以使用 `super` 开头来构建相对路径。这么做类似于文件系统中以 `..` 开头:该路径从 **父** 模块开始而不是当前模块。这在例如示例 7-9 这样的情况下有用处,在这里 `clarinet` 函数通过指定以 `super` 开头的路径调用 `breathe_in` 函数:
<span class="filename">文件名: src/lib.rs</span>
```rust
# fn main() {}
#
mod instrument {
fn clarinet() {
super::breathe_in();
}
}
fn breathe_in() {
// 函数体
}
```
<span class="caption">示例 7-9: 使用以 `super` 开头的路径从父目录开始调用函数</span>
`clarinet` 函数位于 `instrument` 模块中,所以可以使用 `super` 进入 `instrument` 的父模块,也就是根 `crate`。从这里可以找到 `breathe_in`。成功!
你可能想要使用 `super` 开头的相对路而不是以 `crate` 开头的绝对路径的原因是 `super` 可能会使修改有着不同模块层级结构的代码变得更容易,如果定义项和调用项的代码被一同移动的话。例如,如果我们决定将 `instrument` 模块和 `breathe_in` 函数放入 `sound` 模块中,这时我们只需增加 `sound` 模块即可,如示例 7-10 所示。
<span class="filename">文件名: src/lib.rs</span>
```rust
mod sound {
mod instrument {
fn clarinet() {
super::breathe_in();
}
}
fn breathe_in() {
// Function body code goes here
}
}
```
<span class="caption">示例 7-10: 增加一个名为 `sound` 的父模块并不影响相对路径 `super::breathe_in`</span>
示例 7-10 在 `clarinet` 函数中调用 `super::breathe_in` 将如示例 7-9 一样继续有效,无需更新路径。如果在 `clarinet` 函数不使用 `super::breathe_in` 而是使用 `crate::breathe_in` 的话,当增加父模块 `sound` 后,则需要更新 `clarinet` 函数使用 `crate::sound::breathe_in` 路径。使用相对路径可能意味着重新布局模块时需要更少的必要修改。
### 对结构体和枚举使用 `pub`
可以以模块与函数相同的方式来设计公有的结构体和枚举,不过有一些额外的细节。
如果在结构体定义中使用 `pub`,可以使结构体公有。然而结构体的字段仍是私有的。可以在每一个字段的基准上选择其是否公有。在示例 7-11 中定义了一个公有结构体 `plant::Vegetable`,其包含公有的 `name` 字段和私有的 `id` 字段。
<span class="filename">文件名: src/main.rs</span>
```rust
mod plant {
pub struct Vegetable {
pub name: String,
id: i32,
}
impl Vegetable {
pub fn new(name: &str) -> Vegetable {
Vegetable {
name: String::from(name),
id: 1,
}
}
}
}
fn main() {
let mut v = plant::Vegetable::new("squash");
v.name = String::from("butternut squash");
println!("{} are delicious", v.name);
// 如果将如下行取消注释代码将无法编译:
// println!("The ID is {}", v.id);
}
```
<span class="caption">示例 7-11: 结构体带有公有和私有的字段</span>
因为 `plant::Vegetable` 结构体的 `name` 字段使公有的,在 `main` 中可以使用点号读写 `name` 字段。不允许在 `main` 中使用 `id` 字段因为其使私有的。尝试取消注释的行来打印 `id` 字段的值来看看会出现什么错误!另外注意因为 `plant::Vegetable` 有私有字段,需要提供一个公有的关联函数来构建 `Vegetable` 的实例(这里使用了传统的名称 `new`)。如果 `Vegetable` 没有提供这么一个函数,我们就不能在 `main` 中创建 `Vegetable` 的实例,因为在 `main` 中不允许设置私有字段 `id` 的值。
相反,如果有一个公有枚举,其所有成员都是公有。只需在 `enum` 关键词前加上 `pub`,如示例 7-12 所示。
<span class="filename">文件名: src/main.rs</span>
```rust
mod menu {
pub enum Appetizer {
Soup,
Salad,
}
}
fn main() {
let order1 = menu::Appetizer::Soup;
let order2 = menu::Appetizer::Salad;
}
```
<span class="caption">示例 7-12: 将枚举设计为公有会使其所有成员公有</span>
因为 `Appetizer` 枚举是公有的,可以在 `main` 中使用 `Soup` and `Salad` 成员。
还有一种使用 `pub` 的场景我们还没有涉及到,而这是我们最后要讲的模块功能:`use` 关键字。我们先单独介绍 `use`,然后展示如何结合使用 `pub``use`
### 使用 `use` 关键字将名称引入作用域
你可能考虑过本章很多的函数调用的路径是冗长和重复的。例如示例 7-8 中,当我们选择 `clarinet` 函数的绝对或相对路径时,每次想要调用 `clarinet` 时都不得不也指定 `sound``instrument`。幸运的是,有一次性将路径引入作用域然后就像调用本地项那样的方法:使用 `use` 关键字。在示例 7-13 中将 `crate::sound::instrument` 模块引入了 `main` 函数的作用域,以便只需指定 `instrument::clarinet` 来调用 `clarinet` 函数。
<span class="filename">文件名: src/main.rs</span>
```rust
mod sound {
pub mod instrument {
pub fn clarinet() {
// 函数体
}
}
}
use crate::sound::instrument;
fn main() {
instrument::clarinet();
instrument::clarinet();
instrument::clarinet();
}
```
<span class="caption">示例 7-13: 使用 `use` 将模块引入作用域并使用绝对路ing来缩短在模块中调用项所必须的路径</span>
当指定 `use` 后以 `self` 开头的相对路径在未来可能不是必须的;这是一个开发者正在尽力消除的语言中的不一致。
选择使用 `use` 和指定绝对路径,可以使得当调用项的代码移动到模块树的不同位置,不过定义的代码没有移动的情况的代码更新变得更为轻松,这与示例 7-10 中同时移动的情况相对。例如,如果我们决定采用示例 7-13 的代码,将 `main` 函数的行为提取到函数 `clarinet_trio` 中,并将该函数移动到模块 `performance_group` 中,这时 `use` 所指定的路径无需变化,如示例 7-15 所示。
<span class="filename">文件名: src/main.rs</span>
```rust
mod sound {
pub mod instrument {
pub fn clarinet() {
// 函数体
}
}
}
mod performance_group {
use crate::sound::instrument;
pub fn clarinet_trio() {
instrument::clarinet();
instrument::clarinet();
instrument::clarinet();
}
}
fn main() {
performance_group::clarinet_trio();
}
```
<span class="caption">示例 7-15: 移动调用项的代码时绝对路径无需移动</span>
相反,如果对示例 7-14 中指定了相对路径的代码做同样的修改,则需要将 `use
self::sound::instrument` 变为 `use super::sound::instrument`。如果你不确定将来模块树会如何变化,那么选择采用相对或绝对路径是否会减少修改可能全靠猜测,不过本书的作者倾向于通过 `crate` 指定绝对路径,因为定义和调用项的代码更有可能相互独立的在模块树中移动,而不是像示例 7-10 那样一同移动。
### `use` 函数路径使用习惯 VS 其他项
示例 7-13 中,你可能会好奇为什么指定 `use crate::sound::instrument` 接着在 `main` 中调用 `instrument::clarinet`,而不是如示例 7-16 所示的有相同行为的代码:
<span class="filename">文件名: src/main.rs</span>
```rust
mod sound {
pub mod instrument {
pub fn clarinet() {
// 函数体
}
}
}
use crate::sound::instrument::clarinet;
fn main() {
clarinet();
clarinet();
clarinet();
}
```
<span class="caption">示例 7-16: 通过 `use``clarinet` 函数引入作用域,这是不推荐的</span>
对于函数来说,通过 `use` 指定函数的父模块接着指定父模块来调用方法被认为是习惯用法。这么做而不是像示例 7-16 那样通过 `use` 指定函数的路径,清楚的表明了函数不是本地定义的,同时仍最小化了指定全路径时的重复。
对于结构体、枚举和其它项,通过 `use` 指定项的全路径是习惯用法。例如,示例 7-17 展示了将标准库中 `HashMap` 结构体引入作用域的习惯用法。
<span class="filename">文件名: src/main.rs</span>
```rust
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert(1, 2);
}
```
<span class="caption">示例 7-17: 将 `HashMap` 引入作用域的习惯用法</span>
相反,示例 7-18 中的代码将 `HashMap` 的父模块引入作用域不被认为是习惯用法。这个习惯并没有很强制的理由;这是慢慢形成的习惯同时人们习惯于这么读写。
<span class="filename">文件名: src/main.rs</span>
```rust
use std::collections;
fn main() {
let mut map = collections::HashMap::new();
map.insert(1, 2);
}
```
<span class="caption">示例 7-18: 将 `HashMap` 引入作用域的非习惯方法</span>
这个习惯的一个例外是如果 `use` 语句会将两个同名的项引入作用域时,这是不允许的。示例 7-19 展示了如何将两个不同父模块的 `Result` 类型引入作用域并引用它们。
<span class="filename">文件名: src/lib.rs</span>
```rust
use std::fmt;
use std::io;
fn function1() -> fmt::Result {
# Ok(())
}
fn function2() -> io::Result<()> {
# Ok(())
}
```
<span class="caption">示例 7-19: 将两个同名类型引入作用域必须使用父模块</span>
因为如果我们指定 `use std::fmt::Result``use std::io::Result`,则作用域中会有两个 `Result` 类型Rust 无法知道我们想用哪个 `Result`。尝试这么做并看看编译器错误!
### 通过 `as` 关键字重命名引入作用域的类型
将两个同名类型引入同一作用域这个问题还有另一个解决办法:可以通过在 `use` 后加上 `as` 和一个新名称来为此类型指定一个新的本地名称。示例 7-20 展示了另一个编写示例 7-19 中代码的方法,通过 `as` 重命名了其中一个 `Result` 类型。
<span class="filename">文件名: src/lib.rs</span>
```rust
use std::fmt::Result;
use std::io::Result as IoResult;
fn function1() -> Result {
# Ok(())
}
fn function2() -> IoResult<()> {
# Ok(())
}
```
<span class="caption">示例 7-20: 通过 `as` 关键字重命名引入作用域的类型</span>
Loading…
Cancel
Save