将模组拆分为不同文件
Separating Modules into Different Files
到目前为止,本章的全部示例,都是将多个模组定义在一个文件中的。在模组变得大起来时,就会打算将他们的定义,迁移到单独文件,从而令到代码易于导览。
比如,这里就从清单 7-17 中的代码开始,并将那些模组提取到文件中,而非将所有那些模组,都定义在那个代码箱根文件里。在此情况下,代码箱根文件为 src/lib.rs
,但这个过程同样对那些根文件为 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
文件之前,这是不会编译的。
文件名:src/lib.rs
#![allow(unused)] fn main() { mod front_of_house; pub use crate::front_of_house::hosting; pub fn eat_at_restaurant() { hosting::add_to_waitlist(); } }
清单 7-21:声明出其模组代码体将在 src/front_of_house.rs
中的 front_of_house
模组
接下来,就要把原先在花括号中的代码,放入到一个新的名为 src/front_of_house.rs
文件中,如下清单 7-22 中所示。由于编译器在该代码箱根中,找到了名字 front_of_house
,因此他就明白要在这个文件中看看。
文件名:src/front_of_house.rs
#![allow(unused)] fn main() { pub mod hosting { pub fn add_to_waitlist() {} } }
清单 7-22:文件 src/front_of_house.rs
中 front_of_house
模组内部的定义
请注意只需在模组树中的某处,使用一次 mod
声明,而将某个文件的内容加载进来。一旦编译器获悉该文件是项目的一部分(且由已将那个 mod
语句放置于于何处,而掌握了该代码在模组树中所处的位置),项目中的其他文件,则应如同之前 用于引用模组树中项目的路径 小节中,曾讲到的到模组声明处的路径,来引用那个文件中的代码。也就是说,这里的 mod
并非 其他编程语言有的那种 “include” 操作。
接下来,就要将那个 hosting
模组,提取到他自己的文件了。而由于 hosting
是 front_of_house
,而非根模组,的子模组,因此过程略有不同。这里将把 hosting
模组的文件,放在模组树中以其父辈命名的一个新目录中,此示例中即为 src/front_of_house
。
这里要将 src/front_of_house.rs
文件,修改为只包含 hosting
模组声明,以开始对 hosting
的迁移:
文件名:src/front_of_house.rs
#![allow(unused)] fn main() { pub mod hosting; }
随后就要创建一个 src/front_of_house
的目录,和一个文件 src/front_of_house/hosting.rs
,来包含在 hosting
模组中构造的那些定义:
文件名:src/front_of_house/hosting.rs
#![allow(unused)] fn main() { pub fn add_to_waitlist() {} }
相反如果将 hosting.rs
放在 src
目录,那么编译器就会以为 hosting.rs
的代码,是在声明于代码箱根部的 hosting
模组中的,而不是那个 front_of_house
模组的子模组中的。为了获取模组代码,而要查看那些文件方面的编译器规则,就表明这些目录与文件,甚为紧密地于模组树结构相匹配。
备用文件路径
本小节讲的是 Rust 编译器所用到的最惯用的文件路径;但较早的文件路径仍被支持。
对于定义在代码箱根部的名为
front_of_house
模组,编译器会在下面这些地方查找该模组的代码:
src/front_of_house.rs
(即这里讲到的);src/front_of_house/mod.rs
(较早的,仍被支持的路径)。
而对于作为
front_of_house
的子模组的名为hosting
的模组,编译器会在以下地方查找该模组的代码:
src/front_of_house/hosting.rs
(即这里讲到的);src/front_of_house/hosting/mod.rs
(较早的,仍被支持的路径)。
对于同一模组,若同时使用这两种文件路径,那么就会得到一个编译器错误。而对同一项目中的不同模组,采用不同方式的文件路径是被允许的,只是会对那些导览项目的人造成困扰。
使用名为
mod.rs
文件方式的主要缺点,即那样的话,项目最终会以许多名为mod.rs
文件而终结,在代码编辑器中,同时打开这些mod.rs
文件,那么就会感到混乱。
将各个模组的代码,移入到单独文件现在就完成了,而模组树还是保持原来那样。尽管模组定义存在于不同文件中,但是无需任何修改,那个在 eat_at_restaurant
中的函数调用仍会工作。这种技巧,就实现了在模组大小增长时,将其迁移到新的文件中。
请注意 src/lib.rs
中的那个 pub use crate::front_of_house::hosting;
语句,同样不曾改变,而那个 use
也不会对哪些文件作为代码箱的部分,而被编译有任何的影响。mod
关键字定义了模组,而 Rust 则会在与该模组有着同样名字的文件中,查找要进到那个模组中的代码。
本章小节
Rust 实现了包拆分为多个代码箱,进而将代码箱拆分为多个模组,这样就可以从一个模组,对定义在另一模组中的程序项目加以引用。通过指明绝对或相对路径,就可以做到这点。使用 use
语句,就可以将这些程序项目的路径,带入到作用域,如此就可以在那个作用域中,多次用到所带入的程序项目时,使用较简短的路径。默认下模组代码是私有的,但可通过添加 pub
关键字,而将一些定义构造为公开的。
下一章中,就会看看,可在本地组织良好代码中,使用到的标准库中的一些集合数据结构(collection data structures)。