将模块分离到不同的文件中

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

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

首先,我们将模块提取到它自己的文件中。删除 code 括在模块的大括号内,只留下 声明,以便 src/lib.rs 包含代码 如示例 7-21 所示。请注意,在我们创建 src/front_of_house.rs 文件(如示例 7-22 所示)之前,它不会编译。front_of_housefront_of_housemod front_of_house;

文件名: src/lib.rs

mod front_of_house;

pub use crate::front_of_house::hosting;

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

示例 7-21:声明 front_of_house 模块 body 将位于 src/front_of_house.rs

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

文件名: src/front_of_house.rs

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

示例 7-22:src/front_of_house.rsfront_of_house 模块内的定义

请注意,您只需在 模块树。一旦编译器知道该文件是项目的一部分(并且知道 由于您放置了语句的位置,因此代码在模块树中的位置),则项目中的其他文件应引用加载的文件的代码 使用指向声明位置的路径,如“引用路径”中所述 到 Module Tree 中的某个 Item“部分。换句话说,不是您可能在其他 编程语言。modmodmod

接下来,我们将模块提取到其自己的文件中。这个过程有点 不同,因为是 的子模块 ,而不是 root 模块。我们将 的文件放在一个新目录中,该目录将是 以其在模块树中的祖先命名,在本例中为 src/front_of_househostinghostingfront_of_househosting

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

文件名: src/front_of_house.rs

pub mod hosting;

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

文件名: src/front_of_house/hosting.rs

pub fn add_to_waitlist() {}

如果我们改为将 hosting.rs 放在 src 目录中,编译器将 期望 hosting.rs 代码位于 crate 中声明的模块 root,并且未声明为模块的子级。这 编译器的规则,用于检查哪些文件,哪些模块的代码意味着 目录和文件与模块树更匹配。hostingfront_of_house

备用文件路径

到目前为止,我们已经介绍了 Rust 编译器使用的最惯用的文件路径, 但 Rust 也支持旧样式的文件路径。对于在 crate 根目录中 declared 的模块,编译器将查找 module 的代码中:front_of_house

  • src/front_of_house.rs(我们介绍的内容)
  • src/front_of_house/mod.rs (旧样式,仍然支持的路径)

对于名为 的模块,它是 的子模块 , compiler 将在以下位置查找模块的代码:hostingfront_of_house

  • src/front_of_house/hosting.rs (我们介绍的内容)
  • src/front_of_house/hosting/mod.rs (旧样式,仍然支持的路径)

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

使用名为 mod.rs 的文件的样式的主要缺点是,您的 项目最终可能会得到许多名为 mod.rs 的文件,这可能会让人感到困惑 当您在编辑器中同时打开它们时。

我们已将每个模块的代码移动到一个单独的文件中,模块树保持不变 一样。函数调用将在没有任何 修改,即使定义位于不同的文件中。这 技术允许您在模块大小增加时将模块移动到新文件。eat_at_restaurant

请注意,src/lib.rs 中的语句也没有改变,也不会对文件产生任何影响 作为 crate 的一部分进行编译。关键字声明 modules,而 Rust 在与模块同名的文件中查找进入 那个模块。pub use crate::front_of_house::hostingusemod

总结

Rust 允许你将一个包拆分为多个 crate,将一个 crate 拆分为多个模块,因此 您可以从一个模块中引用另一个模块中定义的项。你可以做 这通过指定 absolute 或 relative paths 来实现。这些路径可以引入 scope 替换为 statement 的 API 中,以便使用较短的路径来多次使用 该范围内的项。默认情况下,模块代码是私有的,但你可以将 定义 public 通过添加关键字。usepub

在下一章中,我们将查看 standard 库,您可以在组织整齐的代码中使用。

本文档由官方文档翻译而来,如有差异请以官方英文文档(https://doc.rust-lang.org/)为准