定义模块以控制范围和隐私
在本节中,我们将讨论模块和模块系统的其他部分,
即 paths,它允许您命名项目;这use
关键字带来
path into scope;和pub
关键字将项目设为公共。我们还将讨论
这as
关键字、外部包和 glob 运算符。
模块作弊表
在我们了解模块和路径的详细信息之前,我们在这里提供了一个快速的
参考 modules、paths、use
关键字和pub
关键字工作
以及大多数开发人员如何组织他们的代码。我们要走
通过本章中这些规则中的每一个示例,但这是一个
这是提醒模块工作原理的好地方。
- 从 crate 根开始:编译 crate 时,编译器首先 在 crate 根文件(通常是 src/lib.rs 表示库 crate,src/main.rs 表示二进制 crate)中查找要编译的代码。
- 声明模块:在 crate 根文件中,你可以声明新的模块;
假设你声明了一个 “garden” 模块
mod garden;
.编译器将查找 对于这些位置的模块代码:- 内联,在替换分号后面的大括号内
mod garden
- 在文件 src/garden.rs 中
- 在文件 src/garden/mod.rs 中
- 内联,在替换分号后面的大括号内
- 声明子模块:在 crate 根目录以外的任何文件中,你可以
declare 子模块。例如,您可以声明
mod vegetables;
在 src/garden.rs 中。编译器将在 目录中:- 内联,紧随其后
mod vegetables
,而不是在大括号内 分号 - 在文件 src/garden/vegetables.rs 中
- 在文件 src/garden/vegetables/mod.rs 中
- 内联,紧随其后
- 模块中的代码路径:一旦模块成为 crate 的一部分,您就可以
从同一 crate 中的其他任何位置引用该模块中的代码,只要
在隐私规则允许的情况下,使用 code 的路径。例如,
Asparagus
type 可以在 Garden Vegetables 模块中找到crate::garden::vegetables::Asparagus
. - 私有与公共:模块中的代码与其父级相比是私有的
modules 的 Module。要将模块设为公共模块,请使用
pub mod
而不是mod
.要将公共模块中的项也设为公共,请使用pub
在他们的宣言之前。 - 这
use
关键词:在某个范围内,use
keyword 创建快捷方式 项以减少长路径的重复。在任何可以引用crate::garden::vegetables::Asparagus
中,您可以使用use crate::garden::vegetables::Asparagus;
从那时起,您只需要 写Asparagus
以在 scope 中使用该类型。
在这里,我们创建了一个名为backyard
这说明了这些规则。
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;
pub mod garden;
fn main() {
let plant = Asparagus {};
println!("I'm growing {plant:?}!");
}
这pub mod garden;
line 告诉编译器包含它在 src/garden.rs 中找到的代码,即:
文件名: src/garden.rs
pub mod vegetables;
这里pub mod vegetables;
表示 src/garden/vegetables.rs 中的代码是
也包括。该代码为:
#[derive(Debug)]
pub struct Asparagus {}
现在让我们深入了解这些规则的细节并在实践中演示它们!
在模块中对相关代码进行分组
模块让我们在一个 crate 中组织代码,以实现可读性和易于重用。 模块还允许我们控制项目的隐私,因为 module 默认为 private 的。私有项目是内部实现细节 不可用于外部使用。我们可以选择制作 modules 和 items 在它们中 public,这使它们暴露以允许外部代码使用和依赖 在他们身上。
例如,让我们编写一个库 crate,它提供 餐厅。我们将定义函数的签名,但保留它们的主体 empty 来专注于代码的组织,而不是 实施一家餐厅。
在餐饮业中,餐厅的某些部分称为前台,其他部分称为后台。前台是 客户是;这包括主机就座客户、服务器所在的位置 订单和付款,调酒师制作饮料。后台是 厨师和厨师在厨房工作,洗碗机打扫卫生,经理们负责 行政工作。
要以这种方式构建我们的 crate,我们可以将其函数组织成嵌套的
模块。创建一个名为restaurant
通过运行cargo new restaurant --lib
.然后将示例 7-1 中的代码输入到 src/lib.rs 中,以
定义一些模块和函数签名;此代码是 front of house
部分。
文件名: 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() {}
}
}
示例 7-1:一个front_of_house
包含其他
然后包含函数的模块
我们使用mod
keyword 后跟模块名称
(在本例中为front_of_house
).然后,模块的主体进入 curly 内部
括弧。在模块中,我们可以放置其他模块,就像在本例中使用
模块hosting
和serving
.模块还可以保存其他
项目,比如结构、枚举、常量、特征,以及 清单 中所示
7-1 - 函数。
通过使用模块,我们可以将相关定义组合在一起并命名原因 他们是相关的。使用此代码的程序员可以根据 组,而不必通读所有定义,这让事情变得更容易 以查找与其相关的定义。程序员添加新功能 到此代码将知道将代码放置在何处以保持程序井井有条。
前面我们提到了 src/main.rs 和 src/lib.rs 被称为 crate
根。他们之所以得名,是因为这两个内容中的任何一个
文件组成一个名为crate
在 crate 的 module 结构的根目录中,
称为模块树。
示例 7-2 显示了示例 7-1 中结构的模块树。
crate
└── front_of_house
├── hosting
│ ├── add_to_waitlist
│ └── seat_at_table
└── serving
├── take_order
├── serve_order
└── take_payment
示例 7-2:清单中代码的模块树 7-1
此树显示某些模块如何嵌套在其他模块中;例如hosting
内部嵌套front_of_house
.树还显示一些模块
是同级,这意味着它们在同一模块中定义;hosting
和serving
是front_of_house
.如果模块 A 为
包含在模块 B 中,我们说模块 A 是模块 B 的子项,并且
该模块 B 是模块 A 的父级。请注意,整个模块树
根植在名为crate
.
模块树可能会提醒您 计算机;这是一个非常贴切的比较!就像文件系统中的目录一样, 您可以使用 Modules 来组织您的代码。就像目录中的文件一样,我们 需要一种方法来找到我们的模块。
本文档由官方文档翻译而来,如有差异请以官方英文文档(https://doc.rust-lang.org/)为准