当前位置: 首页 > news >正文

7.5将模块分离到不同的文件中

将模块分离到不同的文件中

到目前为止,本章中的所有示例都在一个文件中定义了多个模块。当模块变得庞大时,你可能希望将它们的定义移到单独的文件中,以便更容易浏览代码。
例如,我们从清单7-17中的代码开始,该代码包含多个餐厅模块。我们将把模块提取到各自的文件,而不是让所有模块都定义在crate根文件中。在这种情况下,crate根文件是src/lib.rs,但这个过程同样适用于二进制crate,其crate根文件是src/main.rs。
首先,我们将front_of_house模块提取到它自己的文件。删除front_of_house模块花括号内的代码,只保留mod front_of_house;声明,这样src/lib.rs就包含了清单7-21所示的代码。注意,在创建清单7-22中的src/front_of_house.rs文件之前,这段代码无法编译。
文件名:src/lib.rs

mod front_of_house;
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}

清单7-21:声明front_of_house模块,其主体将在src/front_of_house.rs中
接下来,将原本位于花括号内的代码放入一个名为src/front_of_house.rs的新文件,如清单7-22所示。编译器知道要查找此文件,因为它遇到了crate根目录下名为front_of_house的模块声明。
文件名:src/front_of_house.rs

pub mod hosting {pub fn add_to_waitlist() {}
}

清单 7-22:位于 src/front_of_house.rs 中 front_of_house 模块内的定义

请注意,在模块树中,你只需使用 mod 声明加载一次文件。一旦编译器知道该文件是项目的一部分(并且因为你放置 mod 语句的位置,知道代码在模块树中的位置),项目中的其他文件应通过声明时所在路径来引用已加载文件的代码,如“模块树中项的路径”一节所述。换句话说,mod 并不是你在其他编程语言中见过的“包含”操作。

接下来,我们将把 hosting 模块提取到它自己的文件中。这个过程有些不同,因为 hosting 是 front_of_house 的子模块,而不是根模块的子模块。我们会将 hosting 文件放入一个新目录,该目录以其祖先命名,在本例中为 src/front_of_house。

开始移动 hosting 时,我们修改 src/front_of_house.rs,使其仅包含对 hosting 模块的声明:

文件名:src/front_of_house.rs

pub mod hosting;

然后我们创建一个 src/front_of_house 目录和一个 hosting.rs 文件,用于存放 hosting 模块中的定义:

文件名:src/front_of_house/hosting.rs

pub fn add_to_waitlist() {}

如果我们把 hosting.rs 放在 src 目录下,编译器会期望该代码属于 crate 根部声明的 hosting 模块,而非作为 front_of_house 子模块声明。编译器检查各个模块对应哪些代码所在文件时,有一套规则,这使得目录和文件结构更贴合模块树结构。

备用路径方式

到目前为止,我们介绍了 Rust 编译器最惯用的路径,但 Rust 同样支持一种较旧风格的路径方式。对于在 crate 根部声明、名为 front_of_house 的模块,编译器会查找以下位置:

  • src/front_of_house.rs(前面介绍过)
  • src/front_of_house/mod.rs(较旧风格,仍被支持)

对于作为 front_of_house 子模块、名为 hosting 的模块,编译器会查找以下位置:

  • src/front_of-house/hosting.rs(前面介绍过)
  • src/front-of-house/hosting/mod.rs(较旧风格,仍被支持)

如果同一模块同时使用这两种风格,会导致编译错误。在同一项目里,不同模组混用这两种风格是允许的,但可能让浏览项目的人感到困惑。

采用 mod.rs 命名方式主要缺点是你的项目可能出现许多叫做 mod.rs 的文件,当你同时打开多个这样的编辑窗口时容易混淆。

我们已经将每个模组代码移至独立文件,并保持了相同的模组树结构。即使定义分布在不同源代码里,对 eat_at_restaurant 函数调用也无需任何改动即可正常工作。这种技巧方便随着模组规模增长,将其拆分成新的源码档案。

需要注意的是,在 src/lib.rs 中 pub use crate::front_of_house::hosting 声明未发生变化,而且 use 不影响哪些源码被当作 crate 一部分进行编译。mod 用于声明模组,而 Rust 会去与该模组名称相符之档案寻找对应实现内容。

总结

Rust 支持将包拆分成多个 crate,以及将 crate 拆分成多个模组,从而可以跨模组选用其中定义项,可通过绝对或相对路径指定这些项。这些路径可借助 use 声明引入作用域,以便多次使用时写出更简短形式。默认情况下,模组内代码是私有;若想公开,则需添加 pub 关键字修饰。

下一章,我们将继续探讨一些…

http://www.dtcms.com/a/307102.html

相关文章:

  • FastAPI入门:表单数据、表单模型、请求文件、请求表单与文件
  • 电商项目统一认证方案设计与实战
  • 《JWT + OAuth2统一认证授权:企业级单点登录方案》
  • 【硬件-笔试面试题】硬件/电子工程师,笔试面试题-50,(知识点:TCP/IP 模型)
  • NSGA-III(Non-dominated Sorting Genetic Algorithm III)简介
  • MySQL数据一致性与主从延迟深度解析:从内核机制到生产实践
  • 数据集相关类代码回顾理解 | DataLoader\datasets.xxx
  • 广东省省考备考(第六十一天7.30)——资料分析、数量(强化训练——重点复习回顾)
  • 数据库初阶笔记
  • JavaWeb笔记14
  • C语言15-构造数据类型、位运算符、内存管理
  • Ⅹ—6.计算机二级综合题15---18套
  • 魔塔社区上文生图大模型对比
  • 涉及实验(随机分组)的一些概念
  • 【UEFI系列】EFI Memory Map内存映射 and type
  • cpp-httplib 线程安全
  • Tableau 2019可视化数据分析软件安装包下载安装教程
  • Java基础面试总结(八股)
  • 【硬件-笔试面试题】硬件/电子工程师,笔试面试题-49,(知识点:OSI模型,物理层、数据链路层、网络层)
  • 复现CLIP(对比语言图像预训练)
  • windows通过WSL配置linux环境
  • 重生之我在10天内卷赢C++ - DAY 2
  • UNet改进(27):对抗注意力机制如何提升UNet的图像分割性能
  • Effective C++ 条款11:在operator=中处理“自我赋值”
  • 【通识】计算机网络
  • 游戏盾能够防御哪些类型攻击?从哪些方面防护?
  • 智能体产品化的关键突破:企业智能化转型的“最后一公里”如何迈过?
  • 【从0开始学习Java | 第8篇】抽象类和接口
  • 力扣热题100---------35.搜索插入为位置
  • NLU 语义解析评测实践:基于函数调用的 ACC、ROUGE 与 BLEU 综合指标