Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help


x-i18n: generated_at: “2026-03-01T13:52:43Z” model: gemini-3-flash-preview provider: google-gemini-cli source_hash: 9a47196bd42516d57eaa32a2813db3f89d404ef3a02f78fb465329acc9c95571 source_path: ch07-02-defining-modules-to-control-scope-and-privacy.md workflow: 16

使用模块控制作用域和私有性 (Control Scope and Privacy with Modules)

Control Scope and Privacy with Modules

在本节中,我们将讨论模块和模块系统的其他部分,即“路径 (paths)”,它们允许你为项命名;use 关键字用于将路径引入作用域;以及 pub 关键字用于使项成为公有的。我们还将讨论 as 关键字、外部包和通配符运算符。

In this section, we’ll talk about modules and other parts of the module system, namely paths, which allow you to name items; the use keyword that brings a path into scope; and the pub keyword to make items public. We’ll also discuss the as keyword, external packages, and the glob operator.

模块速查表 (Modules Cheat Sheet)

Modules Cheat Sheet

在深入了解模块和路径的细节之前,这里我们提供了一个关于模块、路径、use 关键字和 pub 关键字在编译器中如何工作,以及大多数开发人员如何组织代码的快速参考。我们将在本章中贯穿这些规则的示例,但这里是提醒你模块如何工作的绝佳参考。

Before we get to the details of modules and paths, here we provide a quick reference on how modules, paths, the use keyword, and the pub keyword work in the compiler, and how most developers organize their code. We’ll be going through examples of each of these rules throughout this chapter, but this is a great place to refer to as a reminder of how modules work.

  • 从 crate 根开始:编译 crate 时,编译器首先在 crate 根文件(通常库 crate 为 src/lib.rs,二进制 crate 为 src/main.rs)中查找要编译的代码。
  • 声明模块:在 crate 根文件中,你可以声明新模块;假设你用 mod garden; 声明了一个 “garden” 模块。编译器将在这些地方查找该模块的代码:
    • 内联,在紧跟 mod garden 之后取代分号的花括号内
    • 在文件 src/garden.rs
    • 在文件 src/garden/mod.rs
  • 声明子模块:在除 crate 根以外的任何文件中,你都可以声明子模块。例如,你可能在 src/garden.rs 中声明 mod vegetables;。编译器将在以父模块命名的目录中的这些地方查找该子模块的代码:
    • 内联,直接跟在 mod vegetables 之后,在花括号内而不是分号处
    • 在文件 src/garden/vegetables.rs
    • 在文件 src/garden/vegetables/mod.rs
  • 模块中代码的路径:一旦模块成为你的 crate 的一部分,只要私有性规则允许,你就可以从同一 crate 的任何其他地方使用该代码的路径来引用该模块中的代码。例如,garden vegetables 模块中的 Asparagus 类型将在 crate::garden::vegetables::Asparagus 处找到。
  • 私有与公有:默认情况下,模块内的代码对其父模块是私有的。要使模块成为公有的,请使用 pub mod 而不是 mod 声明它。要使公有模块内的项也成为公有的,请在它们的声明之前使用 pub
  • use 关键字:在一个作用域内,use 关键字可以为项创建快捷方式,以减少长路径的重复。在任何可以引用 crate::garden::vegetables::Asparagus 的作用域内,你都可以使用 use crate::garden::vegetables::Asparagus; 创建快捷方式,从此以后,你只需要写 Asparagus 就可以在该作用域内使用该类型。

这里,我们创建一个名为 backyard 的二进制 crate 来阐述这些规则。crate 的目录(也名为 backyard)包含这些文件和目录:

backyard
├── Cargo.lock
├── Cargo.toml
└── src
    ├── garden
    │   └── vegetables.rs
    ├── garden.rs
    └── main.rs

在这种情况下,crate 根文件是 src/main.rs,它包含:

{{#rustdoc_include ../listings/ch07-managing-growing-projects/quick-reference-example/src/main.rs}}

pub mod garden; 这一行告诉编译器包含它在 src/garden.rs 中找到的代码,该代码是:

{{#rustdoc_include ../listings/ch07-managing-growing-projects/quick-reference-example/src/garden.rs}}

在这里,pub mod vegetables; 意味着 src/garden/vegetables.rs 中的代码也被包含了。该代码是:

{{#rustdoc_include ../listings/ch07-managing-growing-projects/quick-reference-example/src/garden/vegetables.rs}}

现在让我们深入了解这些规则的细节,并演示它们的实际应用!

Now let’s get into the details of these rules and demonstrate them in action!

“模块 (Modules)” 让我们能够组织 crate 内的代码,以提高可读性和易重用性。模块还允许我们控制项的“私有性 (privacy)”,因为默认情况下,模块内的代码是私有的。私有项是内部实现细节,不可供外部使用。我们可以选择将模块及其内部的项设为公有的,这将公开它们,允许外部代码使用并依赖它们。

Modules let us organize code within a crate for readability and easy reuse. Modules also allow us to control the privacy of items because code within a module is private by default. Private items are internal implementation details not available for outside use. We can choose to make modules and the items within them public, which exposes them to allow external code to use and depend on them.

作为一个例子,让我们编写一个提供餐厅功能的库 crate。我们将定义函数的签名,但保持其主体为空,以便专注于代码的组织而不是餐厅的实现。

As an example, let’s write a library crate that provides the functionality of a restaurant. We’ll define the signatures of functions but leave their bodies empty to concentrate on the organization of the code rather than the implementation of a restaurant.

在餐饮业中,餐厅的某些部分被称为前厅(front of house),其他部分被称为后勤(back of house)。“前厅”是顾客所在的地方;这包括领位员为顾客安排座位、服务员下单和收款以及调酒师调酒的地方。“后勤”是厨师在厨房工作、洗碗工清理以及经理进行管理工作的地方。

To structure our crate in this way, we can organize its functions into nested modules. Create a new library named restaurant by running cargo new restaurant --lib. Then, enter the code in Listing 7-1 into src/lib.rs to define some modules and function signatures; this code is the front of house section.

{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-01/src/lib.rs}}

我们使用 mod 关键字后跟模块名称(在本例中为 front_of_house)来定义模块。然后,模块的主体放在花括号内。在模块内部,我们可以放置其他模块,就像本例中的 hostingserving 模块一样。模块还可以保存其他项的定义,例如结构体、枚举、常量、特征,以及如示例 7-1 所示的函数。

We define a module with the mod keyword followed by the name of the module (in this case, front_of_house). The body of the module then goes inside curly brackets. Inside modules, we can place other modules, as in this case with the modules hosting and serving. Modules can also hold definitions for other items, such as structs, enums, constants, traits, and as in Listing 7-1, functions.

通过使用模块,我们可以将相关的定义组合在一起,并说明它们为什么相关。使用这些代码的程序员可以根据这些分组来导航代码,而无需阅读所有的定义,从而更容易找到与他们相关的定义。为这些代码添加新功能的程序员将知道代码应该放在哪里,以保持程序井然有序。

By using modules, we can group related definitions together and name why they’re related. Programmers using this code can navigate the code based on the groups rather than having to read through all the definitions, making it easier to find the definitions relevant to them. Programmers adding new functionality to this code would know where to place the code to keep the program organized.

早些时候,我们提到 src/main.rssrc/lib.rs 被称为“crate 根 (crate roots)”。它们之所以得名,是因为这两个文件中的任何一个的内容都会在 crate 模块结构的根部形成一个名为 crate 的模块,这就是所谓的“模块树 (module tree)”。

Earlier, we mentioned that src/main.rs and src/lib.rs are called crate roots. The reason for their name is that the contents of either of these two files form a module named crate at the root of the crate’s module structure, known as the module tree.

示例 7-2 显示了示例 7-1 中结构的模块树。

Listing 7-2 shows the module tree for the structure in Listing 7-1.

crate
 └── front_of_house
     ├── hosting
     │   ├── add_to_waitlist
     │   └── seat_at_table
     └── serving
         ├── take_order
         ├── serve_order
         └── take_payment

这棵树展示了某些模块是如何嵌套在其他模块内部的;例如,hosting 嵌套在 front_of_house 内部。这棵树还显示了一些模块是“兄弟 (siblings)”,这意味着它们在同一个模块中定义;hostingserving 是在 front_of_house 内部定义的兄弟模块。如果模块 A 包含在模块 B 中,我们说模块 A 是模块 B 的“子 (child)”,模块 B 是模块 A 的“父 (parent)”。请注意,整个模块树都植根于名为 crate 的隐式模块下。

This tree shows how some of the modules nest inside other modules; for example, hosting nests inside front_of_house. The tree also shows that some modules are siblings, meaning they’re defined in the same module; hosting and serving are siblings defined within front_of_house. If module A is contained inside module B, we say that module A is the child of module B and that module B is the parent of module A. Notice that the entire module tree is rooted under the implicit module named crate.

模块树可能会让你联想到计算机上的文件系统目录树;这是一个非常贴切的类比!就像文件系统中的目录一样,你使用模块来组织代码。就像目录中的文件一样,我们需要一种方法来找到我们的模块。

The module tree might remind you of the filesystem’s directory tree on your computer; this is a very apt comparison! Just like directories in a filesystem, you use modules to organize your code. And just like files in a directory, we need a way to find our modules.