模块(mod) 是核心的代码组织工具,用于解决命名冲突、控制代码可见性(封装)、拆分大型项目。
- 组织代码结构:把逻辑相关的函数、结构等放在一个模块中,保持代码清晰。
- 控制可见性:模块内的项(如函数、结构等)默认是私有的(
private),根据需要设定其公开性。 - 命名空间管理(作用域隔离):模块支持层级路径访问,可防止命名冲突。
mod与use关系
| 术语 | 本质 | 作用 |
|---|---|---|
| 文件/目录作为 mod 名 | 模块的「物理载体」(单文件 = 单个 mod,目录 = 模块容器) | 物理层面组织代码 |
明确用 mod <name> 声明 | 模块的「编译器注册」(告诉编译器 “这个模块存在,加入项目”) | 逻辑层面注册,将其纳入 crate 的模块树 |
use 语句 | 模块元素的「作用域导入」 | 把已注册模块中的元素导入当前作用域,简化访问 |
定义
模块既可以内联定义(inline module),也可以放在独立文件/目录中。
Rust 项目的根模块由入口文件决定:
- 二进制项目:入口是
src/main.rs,main.rs就是根模块(crate)。 - 库项目:入口是
src/lib.rs,lib.rs是根模块(crate)。
所有模块(文件 / 目录)都需在根模块中通过 mod 注册,才能被访问。
内联模块
在同一个文件内定义模块;用 mod 模块名 { ... } 声明模块。
// 定义根模块下的模块 `math`
mod math {
// 模块内的私有函数(默认私有,仅模块内可访问)
fn square(x: i32) -> i32 {
x * x
}
// 用 `pub` 暴露公共函数(外部可访问)
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
// 嵌套模块(模块可嵌套)
pub mod advanced {
pub fn multiply(a: i32, b: i32) -> i32 {
a * b
}
}
}
fn main() {
// 访问公共函数:通过「模块路径」访问
println!("1+2 = {}", math::add(1, 2)); // 输出:3
// 访问嵌套模块的公共函数
println!("3*4 = {}", math::advanced::multiply(3, 4)); // 输出:12
// 错误:无法访问私有函数 `math::square`(未加 pub)
// println!("5² = {}", math::square(5));
}
文件或目录模块
将模块拆分为多个文件 / 目录,核心规则:
- 一个文件对应一个模块(如
math.rs对应模块math)。 - 一个目录对应一个模块(如
utils/对应模块utils),目录名即为模块名(Rust 1.32以前,需要目录下添加mod.rs声明子模块)。
// 文件模块
src/
├── main.rs # 根模块
└── math.rs # 模块 math(与文件名一致)
// 目录模块
src/
├── main.rs
└── utils/ # 模块 utils(目录)
├── math.rs # 子模块 utils::math
└── game.rs # 子模块 utils::game
可见性
默认是模块私有(仅当前模块及子模块可访问),通过 pub 扩展可见性,支持细粒度控制:
| 关键字 | 可见范围 | 适用场景 |
|---|---|---|
pub | 全局可见 | 暴露公共 API |
pub(crate) | 当前 crate 内所有地方可见 | 内部模块间共享,不对外暴露 |
pub(super) | 当前模块的「父模块」及其后代模块中可见 | 子模块向父模块暴露 |
pub(in 路径) | 在指定路径代表的模块及其所有后代中可见 | 跨多级模块的有限共享 |
| 默认(无修饰) | 当前模块及其后代模块中可见 |
mod outer {
pub fn a() { println!("a: 全局可见"); }
pub(crate) fn b() { println!("b: 仅当前 crate 可见"); }
pub(super) fn c() { println!("c: 仅父模块(根模块)可见"); }
pub(in crate::outer::inner) fn d() { println!("d: 仅 inner 模块可见"); }
mod inner {
pub fn e() {
// 子模块可访问父模块的所有元素(包括私有)
super::a();
super::b();
super::c();
super::d(); // 符合 pub(in crate::outer::inner) 的范围
}
}
}
fn main() {
outer::a(); // 允许:pub 全局可见
outer::b(); // 允许:pub(crate) 仅当前 crate 可见
outer::c(); // 允许:pub(super) 父模块(根模块)可见
// outer::d(); // 错误:d 仅 inner 模块可见
outer::inner::e(); // 允许:e 是 pub 的
}
引用
引用模块内的元素时,需要通过路径(类似文件系统路径):
- 绝对路径:从根模块(
crate) 开始,以crate::开头(crate代表当前项目)。 - 相对路径:从当前模块开始,用
self(当前模块,默认可省略)或super(父模块)导航。
use关键字用于模块导入:
- 导入多个元素:用大括号
{} - 导入全部公共元素:通配符
* - 别名
as:也可解决冲突 - 重导出:
pub use不仅导入元素,还将其重新暴露给外部,常用于简化 API 路径(隐藏内部层级)
注册与导入
当前项目内的源代码文件和内部模块,首次在项目中引入(use )时,必须用 mod 声明注册(在根模块(main.rs/lib.rs)写 mod <mod-name>;)。对于外部依赖(如 serde、prost),通过 Cargo.toml 声明(已在其自身的 lib.rs 中注册过了,无需 mod),直接用 use 导入即可。
- 单文件 mod(如
engine.rs):在根模块(main.rs/lib.rs)写mod engine;(注册); - 目录 mod(如
engine/):在根模块写mod engine { pub mod core; }(注册); - 同一文件内的显式 mod:直接写
mod math { ... }(声明即注册)。
mod注册时,查找规则(以mod game;为例):
- 当前目录下的文件
game.rs - 当前目录下的文件夹
game - 一旦找到其中一个,就会停止继续查找。
注册、引用示例:
// 目录结构
src/
├── main.rs # 根模块(注册所有自定义模块)
├── utils.rs # 单文件模块:通用工具函数(简单逻辑)
└── calc/ # 目录模块:计算核心(复杂逻辑,拆分子模块)
├── base.rs # 子模块 calc::base:基础加减
└── advanced.rs # 子模块 calc::advanced:高级乘除/平方
// main.rs(根模块)
///////////////////////////////////////////////////////////////////////////
// 第一步:mod 注册(告诉编译器“这些模块存在,加入项目”)
// 注意:所有自定义模块(自己写的)都必须在这里注册,否则编译器找不到
///////////////////////////////////////////////////////////////////////////
mod utils; // 注册单文件模块 utils(对应 utils.rs)
// 注册目录模块 calc(对应 calc/ 目录),并声明其下的子模块
mod calc {
pub mod base; // 注册子模块 calc::base(对应 calc/base.rs)
pub mod advanced;// 注册子模块 calc::advanced(对应 calc/advanced.rs)
}
///////////////////////////////////////////////////////////////////////////
// 第二步:use 导入(将已注册模块的元素导入当前作用域,简化访问)
///////////////////////////////////////////////////////////////////////////
// 场景1:导入单个元素(直接使用函数名)
use utils::trim_str;
// 场景2:导入模块(后续通过“模块名::元素”访问,适合模块内多个元素需使用)
use calc::base;
// 场景3:嵌套导入(一次性导入目录模块下的多个子模块元素)
use calc::advanced::{multiply, square_with_format};
// 场景4:别名(解决命名冲突,或简化长模块名/元素名)
use calc::advanced::square as calc_square;
fn main() {
// #####################################################################
// 演示1:不用 use 导入,直接通过“绝对路径”访问(证明 mod 注册后即可使用)
// #####################################################################
let raw_str = " rust mod 示例 ";
let trimmed = crate::utils::trim_str(raw_str); // 绝对路径:crate::utils::trim_str
let add_res = crate::calc::base::add(10, 20); // 绝对路径:crate::calc::base::add
// #####################################################################
// 演示2:用 use 导入后访问(简化路径,适合频繁访问)
// #####################################################################
// 场景1:导入单个元素(直接用 trim_str,无需前缀)
let trimmed2 = trim_str(" use 简化访问 ");
// 场景2:导入模块(用“模块名::元素”访问,适合多个元素)
let sub_res = base::subtract(50, 15); // 导入 base 模块,直接 base::subtract
// 场景3:嵌套导入(直接用元素名,多个元素一次性导入)
let mul_res = multiply(6, 7); // 直接用 multiply(来自 calc::advanced)
let formatted_square = square_with_format(5); // 直接用 square_with_format
// 场景4:别名(用 calc_square 替代 square,避免冲突)
let square_res = calc_square(10); // 别名 calc_square 替代 square
}
4万+






