03 crate / module / 可见性(看懂项目结构与 mod)
本章目标
- 你能从
src/main.rs一眼读懂“这个 crate 由哪些模块组成”。 - 你能理解
mod、use、pub、pub use的组合用法,并在项目里正确组织代码边界。 - 你能在新增文件/目录后让编译器“找到它”,避免常见的模块路径错误。
术语速览(用你熟悉的语言类比)
- crate:一个编译单元(类似一个 npm package / 一个 Maven 模块)
- module:crate 内部的命名空间(类似 TS 的 module/namespace + 文件系统约定)
- item 可见性:
pub决定“外部模块是否可用”(类似public/private,但粒度更细)
从 src/main.rs 读懂 crate 根
本项目的 crate root 是二进制入口:src/main.rs
你会看到类似这样的声明:
mod app;mod components;mod db;mod models;mod pages;mod router;mod services;mod state;mod utils;
这意味着:
- crate 顶层模块包括:
crate::app、crate::db、crate::models等 - 对应文件/目录通常是:
src/app.rs(单文件模块)src/db/mod.rs+src/db/*.rs(目录模块)
“目录模块”是怎么工作的(为什么需要 mod.rs)
Rust 的模块系统会把文件系统映射为模块树:
src/db/mod.rs对应模块:crate::dbsrc/db/asset_repo.rs对应模块:crate::db::asset_repo
在 src/db/mod.rs 中,通过 mod asset_repo; 把子模块挂载进来,随后可以:
- 在
db/mod.rs内部use asset_repo::... - 或者
pub use asset_repo::AssetRepository;作为对外 API(更常见)
use / pub / pub use 的组合(工程里最常用)
1) use:在当前模块引入名字
#![allow(unused)] fn main() { use crate::db::AssetRepository; }
仅影响当前模块的可读性,不改变对外可见性。
2) pub:让 item 对外可见
#![allow(unused)] fn main() { pub struct AssetRepository; }
其他模块才能通过 crate::db::asset_repo::AssetRepository 使用它。
3) pub use:重新导出(re-export)
这是大型项目里非常常见的“门面模式”:
- 内部可以有
crate::db::asset_repo、crate::db::plan_repo等细粒度模块 - 对外只暴露
crate::db::{AssetRepository, PlanRepository, SnapshotRepository}
你可以在 src/db/mod.rs 里看到类似写法:
pub use asset_repo::AssetRepository;pub use plan_repo::PlanRepository;
这样 pages 层就不需要了解 db 的文件拆分细节。
路径系统:crate:: / super:: / self::
这是初学者经常迷路的地方,建议记住这三种“稳定定位”:
crate::xxx:从 crate 根开始(最稳)super::xxx:从父模块开始(重构文件时容易受影响)self::xxx:当前模块(用于更明确的内部引用)
在 src/models/asset_sub_category.rs 里就有典型用法:
use super::Category;:从同目录的父模块models引入Category
常见报错与解决方式
1) file not found for module ...
原因通常是:
- 新增了
src/foo/bar.rs,但没有在src/foo/mod.rs写mod bar; - 或者
mod声明和文件名不一致
2) cannot find type/struct/function ... in this scope
原因通常是:
- 忘了
use ...引入 - 或者 item 没有
pub,跨模块访问被禁止
本章练习(在项目里动手巩固)
练习 A:画出模块树(建议真的画出来)
从 src/main.rs 出发,把顶层模块写出来,然后继续展开:
db:connection、asset_repo、plan_repo、snapshot_repomodels:asset、category、asset_scope、vehicle_type、asset_sub_categorycomponents:asset、plan、snapshot、analysis、layout、common
练习 B:新增一个 utils 子模块(不改业务)
- 新建文件:
src/utils/debug.rs - 在
src/utils/mod.rs增加:pub mod debug; - 在
debug.rs写一个小函数:pub fn dump_routes():打印路由列表(字符串即可)
- 在
src/main.rs或某个页面里临时调用它验证编译通过
你会经历一次完整的“新增模块 → 挂载 → 导入 → 使用”的流程。