Rust 从 0 到 1- 代码组织 - 模块
模块(Modules)让我们可以对一个 crate 中的代码进行组织,以提高可读性与重用性。模块还可以控制代码私有性,即代码是可以被外部代码使用的(即公开的),还是作为一个内部实现,不能被外部代码使用(即私有的)。
下面我们将以一个提供餐馆相关功能的 library crate 来作为例子说明(仅演示代码的组织方式,不关注具体功能逻辑)。餐馆中一般会分前台(front of house)和后台(back of house)。前台是招待顾客的地方,在这里,店主可以为顾客安排座位,服务员接受顾客下单和付款,调酒师会制作饮品。后台则是厨师烹饪,洗碗工洗碗,以及经理做行政工作的地方。
为了让 crate 结构与实际的餐厅结构相同,我们可以参照餐厅的组织结构将代码放置到对应的模块中。首先通过执行 cargo new --lib restaurant,来创建一个新的名为 restaurant 的 lib crate;然后在 src/lib.rs 中来定义模块和函数:
我们通过 mod 关键字定义一个模块,并指定模块的名字(如 front_of_house)。在模块内,我们还可以定义其他的模块,如例子中的 hosting 和 serving 模块。模块中也可以定义其他内容,如结构体、枚举、常量、特性、或者函数。
通过使用模块,我们可以将相关的代码组织到一起,并给他们起一个好名字(即高内聚)。组织良好(包括命名)的代码不仅具有更高的可读性,方便其他人使用代码,可以方便的通过模块名称找到他们需要的代码,并且在给代码增加新功能时,也可以清楚的知道,新的代码应该放在哪里。
在前面我们提到了 src/main.rs 和 src/lib.rs 叫做 crate root。之所以这样叫它们的原因是,这两个文件定义了以“crate 模块”(crate 在这里是模块的名字)作为根的模块结构,即模块树(module tree):
这个树不仅展示了模块之间的嵌套关系(例如,hosting 嵌套在 front_of_house 中);还展示了模块之间的兄弟关系,即它们定义在同一模块中(例如,hosting 和 serving 被一起定义在 front_of_house 中)。如果一个模块 A 被包含在模块 B 中,我们将模块 A 称为模块 B 的子模块,模块 B 则是模块 A 的 父模块。注意,整个模块树的根默认为“crate 模块” 。
模块树很容易让大家想到文件系统的目录树;官方认为这是一个非常恰当的类比!就像用文件系统的文件目录组织文件,我们可以使用模块来组织我们的代码。
将不同模块放到单独的文件中
前面的例子是一个文件中定义多个模块。随着代码的增加,模块变多变大时,我们会想要将它们的放到到单独的文件中,以代码的可读性。
还以前面餐馆的例子举例,我们将 front_of_house 模块放到属于它自己的文件 src/front_of_house.rs 中,src/lib.rs:
src/front_of_house.rs
在 mod front_of_house 后使用分号,而不是花括号,意味着模块的定义在同名的文件中。继续对例子进行重构,将 hosting 模块也提取到其自己的文件中,src/front_of_house.rs:
src/front_of_house/hosting.rs
虽然我们做了以上的重构,但是模块树依然保持相同,eat_at_restaurant 中的函数调用可以无需修改。这让我们可以在模块代码增长时,对代码进行重新组织,而尽量不影响代码的使用者。
以上方法同样适用于以 src/main.rs 为 crate root 的 binary crate。
版权声明: 本文为 InfoQ 作者【山】的原创文章。
原文链接:【http://xie.infoq.cn/article/61c9f98647f0b2df312938962】。文章转载请联系作者。
评论