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:55:41Z” model: gemini-3-flash-preview provider: google-gemini-cli source_hash: f71fdf4512195e4c048c6b9c89e5575fea219332099660464e1b2a279f9d5782 source_path: ch07-05-separating-modules-into-different-files.md workflow: 16

将模块拆分为不同的文件 (Separating Modules into Different Files)

Separating Modules into Different Files

到目前为止,本章中的所有示例都在一个文件中定义了多个模块。当模块变大时,你可能希望将其定义移动到单独的文件中,以使代码更易于导航。

So far, all the examples in this chapter defined multiple modules in one file. When modules get large, you might want to move their definitions to a separate file to make the code easier to navigate.

例如,让我们从示例 7-17 中的代码开始,该代码有多个餐厅模块。我们将把模块提取到文件中,而不是在 crate 根文件中定义所有模块。在这种情况下,crate 根文件是 src/lib.rs,但此过程也适用于 crate 根文件为 src/main.rs 的二进制 crate。

For example, let’s start from the code in Listing 7-17 that had multiple restaurant modules. We’ll extract modules into files instead of having all the modules defined in the crate root file. In this case, the crate root file is src/lib.rs, but this procedure also works with binary crates whose crate root file is src/main.rs.

首先,我们将 front_of_house 模块提取到它自己的文件中。删除 front_of_house 模块花括号内的代码,仅保留 mod front_of_house; 声明,使 src/lib.rs 包含示例 7-21 所示的代码。请注意,在我们在示例 7-22 中创建 src/front_of_house.rs 文件之前,这段代码将无法编译。

First, we’ll extract the front_of_house module to its own file. Remove the code inside the curly brackets for the front_of_house module, leaving only the mod front_of_house; declaration, so that src/lib.rs contains the code shown in Listing 7-21. Note that this won’t compile until we create the src/front_of_house.rs file in Listing 7-22.

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

接下来,将花括号中的代码放入名为 src/front_of_house.rs 的新文件中,如示例 7-22 所示。编译器知道要查找这个文件,因为它在 crate 根中遇到了名为 front_of_house 的模块声明。

Next, place the code that was in the curly brackets into a new file named src/front_of_house.rs, as shown in Listing 7-22. The compiler knows to look in this file because it came across the module declaration in the crate root with the name front_of_house.

{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-21-and-22/src/front_of_house.rs}}

请注意,在模块树中,你只需要使用 mod 声明加载一个文件“一次”。一旦编译器知道该文件是项目的一部分(并且由于你放置 mod 语句的位置,它知道了代码在模块树中的位置),项目中的其他文件应该使用指向声明位置的路径来引用已加载文件的代码,如“在模块树中引用项的路径”部分所述。换句话说,mod “不是”你在其他编程语言中可能见到的“include”操作。

Note that you only need to load a file using a mod declaration once in your module tree. Once the compiler knows the file is part of the project (and knows where in the module tree the code resides because of where you’ve put the mod statement), other files in your project should refer to the loaded file’s code using a path to where it was declared, as covered in the “Paths for Referring to an Item in the Module Tree” section. In other words, mod is not an “include” operation that you may have seen in other programming languages.

接下来,我们将 hosting 模块提取到它自己的文件中。过程略有不同,因为 hostingfront_of_house 的子模块,而不是根模块的子模块。我们将把 hosting 的文件放在一个新目录中,该目录将以其在模块树中的祖先命名,在此例中为 src/front_of_house

Next, we’ll extract the hosting module to its own file. The process is a bit different because hosting is a child module of front_of_house, not of the root module. We’ll place the file for hosting in a new directory that will be named for its ancestors in the module tree, in this case src/front_of_house.

要开始移动 hosting,我们将 src/front_of_house.rs 更改为仅包含 hosting 模块的声明:

To start moving hosting, we change src/front_of_house.rs to contain only the declaration of the hosting module:

{{#rustdoc_include ../listings/ch07-managing-growing-projects/no-listing-02-extracting-hosting/src/front_of_house.rs}}

然后,我们创建一个 src/front_of_house 目录和一个 hosting.rs 文件,以包含在 hosting 模块中所做的定义:

Then, we create a src/front_of_house directory and a hosting.rs file to contain the definitions made in the hosting module:

{{#rustdoc_include ../listings/ch07-managing-growing-projects/no-listing-02-extracting-hosting/src/front_of_house/hosting.rs}}

如果我们转而将 hosting.rs 放在 src 目录中,编译器会期望 hosting.rs 的代码位于在 crate 根中声明的 hosting 模块中,而不是被声明为 front_of_house 模块的子模块。编译器关于检查哪些文件对应哪些模块代码的规则意味着目录和文件能更好地匹配模块树。

If we instead put hosting.rs in the src directory, the compiler would expect the hosting.rs code to be in a hosting module declared in the crate root and not declared as a child of the front_of_house module. The compiler’s rules for which files to check for which modules’ code mean the directories and files more closely match the module tree.

备选文件路径 (Alternate File Paths)

Alternate File Paths

到目前为止,我们已经介绍了 Rust 编译器使用的最惯用的文件路径,但 Rust 也支持旧风格的文件路径。对于在 crate 根中声明的名为 front_of_house 的模块,编译器将在以下位置查找该模块的代码:

So far we’ve covered the most idiomatic file paths the Rust compiler uses, but Rust also supports an older style of file path. For a module named front_of_house declared in the crate root, the compiler will look for the module’s code in:

  • src/front_of_house.rs(我们介绍过的)
  • src/front_of_house/mod.rs(旧风格,仍支持的路径)

对于作为 front_of_house 子模块的名为 hosting 的模块,编译器将在以下位置查找该模块的代码:

For a module named hosting that is a submodule of front_of_house, the compiler will look for the module’s code in:

  • src/front_of_house/hosting.rs(我们介绍过的)
  • src/front_of_house/hosting/mod.rs(旧风格,仍支持的路径)

如果你对同一个模块同时使用两种风格,你将得到一个编译器错误。在同一个项目中的不同模块混用两种风格是允许的,但可能会让导航你项目的人感到困惑。

If you use both styles for the same module, you’ll get a compiler error. Using a mix of both styles for different modules in the same project is allowed but might be confusing for people navigating your project.

使用名为 mod.rs 文件的主要缺点是你的项目最终可能会有很多名为 mod.rs 的文件,当你同时在编辑器中打开它们时,这可能会变得很混乱。

The main downside to the style that uses files named mod.rs is that your project can end up with many files named mod.rs, which can get confusing when you have them open in your editor at the same time.

我们已经将每个模块的代码移动到了单独的文件中,模块树保持不变。eat_at_restaurant 中的函数调用将无需任何修改即可工作,尽管定义位于不同的文件中。这种技术让你可以随着模块规模的增长将其移动到新文件中。

We’ve moved each module’s code to a separate file, and the module tree remains the same. The function calls in eat_at_restaurant will work without any modification, even though the definitions live in different files. This technique lets you move modules to new files as they grow in size.

请注意,src/lib.rs 中的 pub use crate::front_of_house::hosting 语句也没有改变,use 对哪些文件作为 crate 的一部分被编译也没有任何影响。mod 关键字声明模块,而 Rust 会在与模块同名的文件中查找进入该模块的代码。

Note that the pub use crate::front_of_house::hosting statement in src/lib.rs also hasn’t changed, nor does use have any impact on what files are compiled as part of the crate. The mod keyword declares modules, and Rust looks in a file with the same name as the module for the code that goes into that module.

总结 (Summary)

Summary

Rust 允许你将一个包拆分为多个 crate,并将一个 crate 拆分为模块,以便你可以从另一个模块中引用一个模块中定义的项。你可以通过指定绝对或相对路径来实现这一点。这些路径可以通过 use 语句引入作用域,以便你可以在该作用域内多次使用该项时使用较短的路径。模块代码默认是私有的,但你可以通过添加 pub 关键字使定义成为公有的。

Rust lets you split a package into multiple crates and a crate into modules so that you can refer to items defined in one module from another module. You can do this by specifying absolute or relative paths. These paths can be brought into scope with a use statement so that you can use a shorter path for multiple uses of the item in that scope. Module code is private by default, but you can make definitions public by adding the pub keyword.

在下一章中,我们将研究标准库中的一些集合数据结构,你可以在你整齐组织的代码中使用它们。

In the next chapter, we’ll look at some collection data structures in the standard library that you can use in your neatly organized code.