将模块分离到不同的文件中
到目前为止,本章中的所有示例都在一个文件中定义了多个模块。当模块变大时,您可能希望将其定义移动到单独的文件中,以使代码更易于导航。
例如,让我们从示例 7-17 中的代码开始,该代码具有多个
restaurant 模块。我们将模块提取到文件中,而不是将所有
modules 中定义的 crate 根文件。在这种情况下,crate 根文件为
src/lib.rs,但此过程也适用于 crate 根文件为 src/main.rs 的二进制 crate。
首先,我们将 front_of_house
模块提取到它自己的文件中。删除 front_of_house
模块的大括号内的代码,只留下 mod front_of_house;
声明,以便 src/lib.rs 包含代码
如示例 7-21 所示。请注意,在我们创建
src/front_of_house.rs 文件。
文件名: 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
模块,其主体将位于 src/front_of_house.rs 中
接下来,将大括号中的代码放入名为
src/front_of_house.rs,如示例 7-22 所示。编译器知道要查看此文件,因为它在 crate 根目录中遇到了名为 front_of_house
的模块声明。
文件名: src/front_of_house.rs
pub mod hosting {
pub fn add_to_waitlist() {}
}
示例 7-22:front_of_house
中的定义
src/front_of_house.rs 中的 module
请注意,你只需要在模块树中使用 mod
声明加载一次文件。一旦编译器知道该文件是项目的一部分(并且知道代码在模块树中的位置,因为你把 mod
放在哪里
语句),则项目中的其他文件应引用加载的文件的代码
使用指向声明位置的路径,如“引用路径”中所述
到 Module Tree 中的某个 Item“部分。换句话说,
mod
不是您可能在其他编程语言中看到的 “include”作。
接下来,我们将 hosting
模块提取到它自己的文件中。这个过程有点不同,因为 hosting
是 front_of_house
的子模块,而不是根模块的子模块。我们将用于托管
的文件放在一个新目录中,该目录将以其在模块树中的祖先命名,在本例中为 src/front_of_house。
要开始移动主机
,我们将 src/front_of_house.rs 更改为仅包含 hosting
模块的声明:
文件名: src/front_of_house.rs
Pub Mod 托管;
然后我们创建一个 src/front_of_house 目录和一个 hosting.rs 文件来包含在 hosting
模块中所做的定义:
文件名: src/front_of_house/hosting.rs
pub fn add_to_waitlist() {}
如果我们改为将 hosting.rs 放在 src 目录中,编译器将期望 hosting.rs 代码位于 crate 根中声明的托管
模块中,而不是声明为 front_of_house
模块的子模块。编译器关于要检查哪些文件、哪些模块代码的规则意味着目录和文件与模块树更紧密匹配。
备用文件路径
到目前为止,我们已经介绍了 Rust 编译器使用的最惯用的文件路径,
但 Rust 也支持旧样式的文件路径。对于名为
front_of_house
crate 根中声明,编译器将在以下位置查找模块的代码:
src/front_of_house.rs (我们介绍的内容)
src/front_of_house/mod.rs (旧样式,仍然支持的路径)
对于名为 hosting
的模块,如果它是 front_of_house
的子模块,编译器将在以下位置查找该模块的代码:
src/front_of_house/hosting.rs (我们介绍的内容)
src/front_of_house/hosting/mod.rs (旧样式,仍然支持的路径)
如果你对同一个模块使用这两种样式,你将得到一个编译器错误。允许对同一项目中的不同模块混合使用这两种样式,但可能会让浏览项目的人感到困惑。
使用名为 mod.rs 的文件的样式的主要缺点是,您的项目最终可能会包含许多名为 mod.rs 的文件,当您在编辑器中同时打开这些文件时,这可能会造成混淆。
我们已将每个模块的代码移动到一个单独的文件中,模块树保持不变。eat_at_restaurant
中的函数调用无需任何修改即可工作,即使定义位于不同的文件中。此技术允许您在模块大小增加时将模块移动到新文件。
请注意, pub use crate::front_of_house::hosting
中的
src/lib.rs 也没有改变,use
也不会影响作为 crate 的一部分编译的文件。mod
关键字声明 modules,Rust 在与模块同名的文件中查找进入该模块的代码。
总结
Rust 允许你把一个包拆分成多个 crate,把一个 crate 拆分成多个模块,这样你就可以从一个模块中引用另一个模块中定义的项目。您可以通过指定绝对或相对路径来执行此作。可以使用 use
语句将这些路径引入范围,以便您可以使用较短的路径来多次使用该范围内的项。默认情况下,模块代码是私有的,但您可以通过添加 pub
关键字将定义设为公共。
在下一章中,我们将介绍标准库中的一些集合数据结构,你可以在组织整齐的代码中使用它们。