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

将模块拆分为不同的文件

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 root 文件中定义所有模块。在这种情况下,crate root 文件是 src/lib.rs,但此过程也适用于 crate root 文件为 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.

mod front_of_house;

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

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

pub mod hosting {
    pub fn add_to_waitlist() {}
}

注意,在模块树中,你只需要使用 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:

pub mod hosting;

然后,我们创建一个 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:

pub fn add_to_waitlist() {}

如果我们相反将 hosting.rs 放在 src 目录中,编译器会期望 hosting.rs 的代码位于 crate root 中声明的 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

到目前为止,我们已经介绍了 Rust 编译器使用的最惯用的文件路径,但 Rust 也支持一种旧式的文件路径。对于在 crate root 中声明的名为 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.rs (what we covered)
  • src/front_of_house/mod.rs(旧式路径,仍然支持)
  • src/front_of_house/mod.rs (older style, still supported path)

对于作为 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.rs (what we covered)
  • src/front_of_house/hosting/mod.rs(旧式路径,仍然支持)
  • src/front_of_house/hosting/mod.rs (older style, still supported path)

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

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

Rust 允许你将 package 拆分为多个 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.