

这里继续沿用上次工程rust-demo
在这一节中,我们将讨论模块和模块系统的其他部分,即允许您命名项目的路径paths;将路径带入范围的use关键字;和pub关键字来公开项目。我们还将讨论as关键字、外部包和glob操作符。
首先,我们将从一个规则列表开始,以便在您将来组织代码时参考。然后我们将详细解释每一个规则。
下面是模块、路径、use关键字和pub关键字在编译器中的工作方式,以及大多数开发人员如何组织他们的代码。我们将浏览每一个规则的例子,但是这是一个很好的地方来回顾模块是如何工作的。
Asparagus类型)。Asparagus,就可以在作用域中使用该类型。这里有一个名为“backyard ”的二进制箱crate来说明这些规则。箱crate的目录,也称为backyard ,包含这些文件和目录:
- backyard // 目录结构
- ├── Cargo.lock
- ├── Cargo.toml
- └── src
- ├── garden
- │ └── vegetables.rs
- ├── garden.rs
- └── main.rs
箱crate的根文件,在本例中为src/main.rs,包含:
文件名:src/main.rs
- use crate::garden::vegetables::Asparagus; // use关键字
-
- pub mod garden; // pub关键字声明模块garden
-
- fn main() {
- let plant = Asparagus {};
- println!("I'm growing {:?}!", plant);
- }
pub mod garden:意味着编译器包含它在src/garden.rs中找到的代码,即:
文件名:src/garden.rs
pub mod vegetables; // 声明模块vegetables是公共的
pub mod vegetables:表示src/garden/vegetables.rs中的代码也包括在内:
- #[derive(Debug)]
- pub struct Asparagus {}
模块让我们将一个箱crate中的代码组织成组,以便于阅读和重用。模块还控制项目的隐私,即项目是否可以由外部代码使用(public)或者是内部实现细节而不能供外部使用(private)。
举个例子,让我们写一个提供餐馆功能的图书馆箱crate。我们将定义函数的签名,但将它们的主体留空,以便专注于代码的组织,而不是用代码实际实现一个餐馆。
在餐饮业中,餐馆的一些部分被称为前厅,另一些被称为后厅。房子的前面是顾客所在的地方;这里是主人招待顾客、服务员接受订单和付款、调酒师调酒的地方。房子的后面是厨师和厨师在厨房工作的地方,洗碗工打扫卫生,经理做行政工作。
为了像真正的餐馆一样构建我们的箱crate,我们可以将功能组织成嵌套的模块。通过运行cargo new - lib restaurant创建一个名为restaurant的新库;然后把下述的代码放到src/lib.rs中,定义一些模块和函数签名。
文件名:src/lib.rs
- mod front_of_house { // 模块嵌套
- mod hosting {
- fn add_to_waitlist() {}
-
- fn seat_at_table() {}
- }
-
- mod serving {
- fn take_order() {}
-
- fn serve_order() {}
-
- fn take_payment() {}
- }
- }
我们通过以mod关键字开始定义一个模块,然后指定模块的名称(在本例中是front_of_house ),并在模块体周围放置花括号。在模块内部,我们可以有其他模块,就像在这个例子中的模块hosting和serving。模块也可以保存其他项目的定义,比如结构、枚举、常量、特征或者——如上例所示——函数。
通过使用模块,我们可以将相关的定义组合在一起,并命名它们为什么相关。使用这种代码的程序员将更容易找到他们想要使用的定义,因为他们可以根据组来导航代码,而不必通读所有的定义。向代码中添加新功能的程序员会知道将代码放在哪里以保持程序有条理。
前面我们提到src/main.rs和src/lib.rs称为箱crate根。之所以有这样的名字,是因为这两个文件中的任何一个文件的内容在crate的模块结构的根上形成了一个名为crate的模块,称为模块树。
下面显示了上例中结构的模块树。
- crate
- └── front_of_house
- ├── hosting
- │ ├── add_to_waitlist
- │ └── seat_at_table
- └── serving
- ├── take_order
- ├── serve_order
- └── take_payment
这个树显示了一些模块如何嵌套在另一个模块中(例如,在front_of_house中有hosting嵌套)。该树还显示了一些模块是彼此的兄弟,这意味着它们是在同一个模块中定义的(hosting和serving是在front_of_house中定义的)。继续家族隐喻,如果模块A包含在模块B中,我们说模块A是模块B的子模块,模块B是模块A的父模块。注意,整个模块树的根在名为crate的隐式模块下。
模块树可能会提醒您计算机上文件系统的目录树;这是一个非常贴切的比喻!就像文件系统中的目录一样,您使用模块来组织您的代码。就像目录中的文件一样,我们需要一种方法来找到我们的模块。