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