Rust 模块、crate 与可见性
crate/module 树如何组织代码;pub 可见性边界;path 与 use 的工程习惯。
#concept
#growing
#dev
#rust
[!info] related notes
Rust 模块、crate 与可见性
这个概念为什么出现
代码增长后必须回答:谁可以调用谁?文件如何拆?
Rust 用 crate 为编译单元、module 为命名与可见性树、pub 控制边界。
[!abstract] 一句话理解 每个 crate 有一棵模块树;默认私有;
pub/pub(crate)等精确导出;use将路径导入作用域。
最小可运行示例
场景:计价 crate 内部模块——对外只导出 quote
下面在单个二进制中演示模块门面;要供外部 crate 使用,将模块和重导出放入 src/lib.rs,再由 bin 或集成测试调用公共 API。
// 业务意图:隐藏内部税率细节,仅导出报价函数。
// 教学点:mod 树;pub(crate);pub use 重导出。
mod tax {
pub(crate) fn rate_bps() -> u32 { 1000 } // 10%
}
mod pricing {
use super::tax;
pub fn quote_total(net_cents: u32) -> u64 {
let net = u64::from(net_cents);
net + net * u64::from(tax::rate_bps()) / 10_000
}
}
pub use pricing::quote_total;
fn main() {
println!("total={}", quote_total(1000));
}
建议运行:cargo run
期望输出:
total=1100
结合场景再看三个关注点
- 内部
tax不对外 pub use做门面- 文件模块:
mod pricing;+pricing.rs同理
核心概念与准确模型
| 概念 | 含义 |
|---|---|
| package | Cargo.toml 对应单位 |
| crate | 编译单元(lib/bin) |
| module | 树节点 |
| path | crate::/super::/self:: |
默认私有项对定义模块与其子模块可见;pub(crate) 仅当前 crate,pub(super) 仅父模块范围,pub(in path) 限制到祖先模块。pub 项还需可访问路径或公共重导出;同一 package 的 lib 与 bin 也是不同 crate,bin 不能访问 lib 的 pub(crate)。
设计动机
- 封装不靠文件名约定 alone
- 明确 API 面
- 支持大代码库演进
边界与误区
- 过度
pub泄漏实现 - 循环模块依赖需重构
mod.rsvs 文件名模块风格(现代偏好foo.rs+foo/)
[!warning] 常见误区:把所有东西 pub 公共 API 是承诺;能 crate 内私有就私有。
工程实践
- 二进制 thin,逻辑在 lib
- 门面重导出稳定路径
- 集成测试只碰公共 API
- 用
cargo doc审视公开面
本节总结
- 模块树 + 可见性
- crate 边界
- use/pub use 管理路径
自测题
- package 与 crate 差别?
pub(crate)适用?
参考答案
- package 可含多个 crate(lib+bin…)。
- 同 crate 共享、不对外部承诺的 API。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| The Book — Packages Modules | 官方书 | 模块系统 |
| Rust Reference — Visibility | 规范 | 可见性 |