定义模块以控制范围和隐私

在本节中,我们将讨论模块和模块系统的其他部分, 即 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 的路径。例如,Asparagustype 可以在 Garden Vegetables 模块中找到crate::garden::vegetables::Asparagus.
  • 私有与公共:模块中的代码与其父级相比是私有的 modules 的 Module。要将模块设为公共模块,请使用pub mod而不是mod.要将公共模块中的项也设为公共,请使用pub在他们的宣言之前。
  • use关键词:在某个范围内,usekeyword 创建快捷方式 项以减少长路径的重复。在任何可以引用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包含其他 然后包含函数的模块

我们使用modkeyword 后跟模块名称 (在本例中为front_of_house).然后,模块的主体进入 curly 内部 括弧。在模块中,我们可以放置其他模块,就像在本例中使用 模块hostingserving.模块还可以保存其他 项目,比如结构、枚举、常量、特征,以及 清单 中所示 7-1 - 函数。

通过使用模块,我们可以将相关定义组合在一起并命名原因 他们是相关的。使用此代码的程序员可以根据 组,而不必通读所有定义,这让事情变得更容易 以查找与其相关的定义。程序员添加新功能 到此代码将知道将代码放置在何处以保持程序井井有条。

前面我们提到了 src/main.rssrc/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.树还显示一些模块 是同级,这意味着它们在同一模块中定义;hostingservingfront_of_house.如果模块 A 为 包含在模块 B 中,我们说模块 A 是模块 B 的子项,并且 该模块 B 是模块 A 的父级。请注意,整个模块树 根植在名为crate.

模块树可能会提醒您 计算机;这是一个非常贴切的比较!就像文件系统中的目录一样, 您可以使用 Modules 来组织您的代码。就像目录中的文件一样,我们 需要一种方法来找到我们的模块。

本文档由官方文档翻译而来,如有差异请以官方英文文档(https://doc.rust-lang.org/)为准