当前位置: 首页 > 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.lryc.cn/news/605430.html

相关文章:

  • 【JEECG】BasicTable单元格编辑,插槽添加下拉组件样式错位
  • 跳跃表可视化深度解析:动态演示数据结构核心原理
  • Docker-01.Docker课程介绍
  • 分层解耦(Controller,Service,Dao)
  • 从映射到共生:元宇宙、物联网与AI的智能融合生态图谱
  • nav2--安装/教程
  • 如何保证数据库的持久性与一致性:从 Linux 磁盘缓存策略到 MySQL 的设计
  • [SKE]使用gmssl库实现AES、SM4、DES、RSA、3DES_EDE和3DES_EEE算法的加密/解密参考模型
  • GitPython01-依赖排查
  • 8. 网络层
  • Linux系统编程Day1-- 免费云服务器获取以及登录操作
  • 【25届数字IC秋招总结】面试经验12——海康威视
  • LeetCode 面试经典 150_数组/字符串_轮转数组(6_189_C++_中等)(额外数组;转置)
  • DIV 指令概述
  • kali Linux 2025.2安装教程(解决安装失败-图文教程超详细)
  • web服务器nginx
  • RNN、LSTM、Transformer推荐博文
  • Spring AI 海运管理应用
  • Django常见模型字段
  • 30道JS高频经典笔试题集合+详解(一)
  • LTE广播信道
  • 基于Java对于PostgreSQL多层嵌套JSON 字段判重
  • 视觉语言模型在视觉任务上的研究综述
  • 微服务的编程测评系统8-题库管理-竞赛管理
  • 闸机控制系统从设计到实现全解析 第 2 篇:数据库设计与 SqlSugar 集成方案
  • Mysql事务原理
  • HPC超算、集群计算
  • 下拉加载问题
  • HTML应用指南:利用POST请求获取全国公牛门店位置信息
  • Elasticsearch(ES)基础语法(笔记)(持续更新)