Rust 模块:mod 关键字与 pub 修饰符
Rust 的模块系统用于组织代码,控制可见性,并避免命名冲突。核心机制由 mod 关键字和 pub 修饰符构成。掌握这两者,就能清晰地划分代码结构、封装内部逻辑,并安全地暴露接口。
创建模块:使用 mod 关键字
定义一个模块,在文件中使用 mod 关键字后跟模块名。
-
在当前文件内定义模块:直接用花括号包裹内容。
mod network { fn connect() { println!("Connecting..."); } } -
从单独文件加载模块:省略花括号,Rust 会自动查找同名文件。
- 假设主文件是
main.rs或lib.rs。 - 创建一个名为
network.rs的文件。 - 在主文件中写:
mod network; - Rust 会自动加载
network.rs的内容作为network模块。
- 假设主文件是
-
从目录加载模块:当模块内容较多时,可将其放入目录。
- 创建目录
network/。 - 在目录内创建
mod.rs文件(这是该目录的入口)。 - 在主文件中写:
mod network; - Rust 会将
network/mod.rs视为network模块的内容。
- 创建目录
注意:从 Rust 2018 起,也可以不用
mod.rs,直接用network/network.rs配合mod network;,但传统方式仍广泛使用。
控制可见性:使用 pub 修饰符
默认情况下,模块内的所有项(函数、结构体、常量等)都是私有的,外部无法访问。使用 pub 将项公开。
-
公开单个项:在函数、结构体等前面加
pub。mod math { pub fn add(a: i32, b: i32) -> i32 { a + b } fn internal_helper() {} // 私有,外部不可见 } -
公开整个模块:在
mod前加pub,使该模块可被父模块之外的代码引用。pub mod utils { pub fn log(msg: &str) { println!("{}", msg); } } -
在其他模块中使用公开项:
- 通过路径访问:
math::add(1, 2) - 或先引入作用域:
use math::add;,然后直接调用add(1, 2)
- 通过路径访问:
模块路径与 use 声明
Rust 使用路径来定位项,分为绝对路径(从 crate 根开始)和相对路径(从当前模块开始)。
-
绝对路径以
crate::开头:crate::network::connect(); -
相对路径使用
self::或super:::self::表示当前模块super::表示父模块self::math::add(3, 4); super::config::get_port();
-
简化路径:使用
use引入:- 引入模块:
use network;→ 可用network::connect() - 引入具体项:
use network::connect;→ 可直接调用connect() - 引入多个项:
use math::{add, subtract}; - 重命名:
use std::fmt::Result as FmtResult;
- 引入模块:
实际项目结构示例
假设你正在开发一个命令行工具,项目结构如下:
src/
├── main.rs
├── config.rs
└── utils/
├── mod.rs
└── logger.rs
-
在
main.rs中声明模块:mod config; mod utils; fn main() { let port = config::get_port(); utils::logger::init(); } -
在
config.rs中公开函数:pub fn get_port() -> u16 { 8080 } -
在
utils/mod.rs中声明子模块并公开:pub mod logger; -
在
utils/logger.rs中定义公开函数:pub fn init() { println!("Logger initialized"); }
这样,main.rs 就能顺利调用 config::get_port() 和 utils::logger::init()。
pub 的进阶用法:选择性公开
pub 不仅可以完全公开,还能限制公开范围。
-
pub(crate):仅在当前 crate 内公开,外部 crate 不可见。pub(crate) fn internal_api() {} -
pub(super):仅对父模块公开。pub(super) fn helper() {} -
pub(in path):仅在指定路径下公开。pub(in crate::network) fn debug_info() {}
这些修饰符帮助你在大型项目中精细控制封装边界,既保证内部协作,又防止外部误用。
常见错误与排查
-
“cannot find function” 错误:
- 检查函数是否标记了
pub - 检查模块是否用
pub mod声明(如果需要跨模块访问) - 检查
use路径是否正确
- 检查函数是否标记了
-
模块文件未被加载:
- 确保在父模块中写了
mod xxx; - 文件名必须与模块名一致(如
mod db;对应db.rs或db/mod.rs)
- 确保在父模块中写了
-
循环依赖:
- 避免模块 A 引用模块 B,同时模块 B 又引用模块 A
- 解决方法:将共享类型提取到第三个模块,或使用 trait 抽象
最佳实践总结
| 场景 | 推荐做法 |
|---|---|
| 小型功能集合 | 单文件模块,用 mod { ... } 内联定义 |
| 独立组件(如网络、数据库) | 单独 .rs 文件,配合 mod name; |
| 复杂子系统 | 目录 + mod.rs 结构 |
| 公共 API | 所有对外项必须加 pub,模块本身也需 pub mod |
| 内部工具函数 | 不加 pub,保持私有 |
始终问自己:这个函数/类型是否需要被其他模块使用?只有答案是“是”,才加 pub。过度公开会增加维护成本,破坏封装性。
模块系统是 Rust 安全性和可维护性的基石。合理使用 mod 和 pub,你的代码将层次分明、边界清晰、易于测试和复用。

暂无评论,快来抢沙发吧!