一句话总结
Rust 用四层概念组织代码:Package(包)→ Crate(编译单元)→ Module(模块)→ 条目.
cargo 贯穿始终,角色相当于 Go 的 go 命令 + go.mod.
本篇厘清这套层级,模块拆分,可见性与测试组织,并对照 Go 的 module/package.
四层组织结构
初学者最容易混淆 package,crate,module 的关系,先用一张表锚定:
| Rust 概念 | 含义 | Go 类比 |
|---|---|---|
| Package | 一个 Cargo.toml 管理的项目,可含多个 crate |
一个 module(go.mod) |
| Crate | 一次编译的根单元,分二进制 crate 和库 crate | 最终的可执行程序 / 库 |
| Module | crate 内部的命名空间,控制可见性 | Go 的 package |
| 条目(item) | 函数,结构体,Trait 等 | 同名概念 |
命名陷阱:Rust 的 module 约等于 Go 的 package
这是 Go 程序员最易踩的术语错位.Go 的 "package"(代码组织/可见性单元)对应的是 Rust 的 module,而不是 Rust 的 "package".
Rust 的 "package" 更接近 Go 的 "module"(go.mod 项目).记住这层错位,后面就不乱了.
两种 crate
- 二进制 crate(binary):有
main函数,编译成可执行程序.入口src/main.rs. - 库 crate(library):没有
main,供其他 crate 引用.入口src/lib.rs.
一个 package 最多一个库 crate,但可有多个二进制 crate(放在 src/bin/ 下).这比 Go "一个目录一个 package" 的规则更灵活.一个常见的项目结构是"库 + 薄二进制":核心逻辑放 lib.rs,main.rs 只做命令行入口,调用库--这样核心逻辑可被测试,也可被别的 crate 复用.
模块:用 mod 划分命名空间
模块在 crate 内部组织代码,控制可见性.可以内联定义:
|
把模块拆成文件
模块变大就该拆成独立文件.mod network;(不带花括号)告诉编译器去对应文件找内容.这点和 Go 按目录自动归集不同--Rust 要显式声明模块树:
|
|
可见性:pub 与默认私有
Rust 的默认可见性是私有:模块里的条目默认只在本模块(及子模块)可见,要对外暴露必须加 pub:
| Go | Rust | |
|---|---|---|
| 导出规则 | 首字母大写即导出 | 显式加 pub |
| 默认 | 小写 = 包内私有 | 无 pub = 模块私有 |
| 粒度 | 包级 | 可细到 pub(crate),pub(super) |
|
Go 靠"首字母大小写"控制导出,简洁但只有"导出/不导出"两档.
Rust 用 pub 关键字,虽啰嗦,却能精细到 pub(crate)(仅本 crate),pub(super)(仅父模块)等多档,适合大型项目精确控制 API 边界.
use:引入路径
每次写全路径 network::server::start() 很累.use 把路径引入当前作用域,类似 Go 的 import:
|
路径关键字与 prelude
crate::-- 从当前 crate 根开始(类似绝对路径)self::-- 当前模块;super::-- 父模块(类似../)
另外,String,Vec,Option 从没 use 过却能直接用,是因为它们在标准库 prelude 里--一组自动引入每个程序的常用条目,类似 Go 内置的 len,make.
测试组织:就写在源码里
Rust 的测试是语言内建的,组织方式很有特色--单元测试通常和被测代码写在同一文件,放在一个带 #[cfg(test)] 的模块里(该模块只在测试时编译):
|
| 测试类型 | 位置 | 能测什么 |
|---|---|---|
| 单元测试 | 源码文件内 #[cfg(test)] mod tests |
含私有函数(同模块可见) |
| 集成测试 | 项目根的 tests/ 目录 |
只能测公开 API(像外部用户) |
运行用 cargo test(第 01 篇见过).和 Go 把测试放在 _test.go 文件不同,Rust 单元测试就嵌在源码里,use super::* 让它能访问同模块的私有项--这是 Rust 能直接测私有函数的原因.
工作空间:管理多 crate 项目
大型项目可用 workspace 把多个相关 crate 组织在一起,共享依赖与构建缓存,类似 Go 的 go.work:
|
入门阶段单 crate 足够,等项目变大,需要拆分库时再了解 workspace 即可.
快速回顾
- 四层结构:Package → Crate → Module → 条目;注意 Rust 的 module 约等于 Go 的 package.
- 两种 crate:二进制(
main.rs)与库(lib.rs);常见"库 + 薄二进制"结构便于测试与复用. - 模块树需显式声明:
mod xxx;引入文件,而非按目录自动归集. - 可见性:默认私有,
pub导出,支持pub(crate)等精细档位,比 Go 大小写更细. - use:引入路径;
crate::/self::/super::定位;prelude 自动引入常用类型. - 测试:单元测试用
#[cfg(test)] mod tests嵌在源码里(可测私有),集成测试放tests/;cargo test运行.
动手练习
- 内联模块:在
main.rs内联定义一个含嵌套子模块的mod,用全路径调用其中的pub fn. - 文件拆分:把上题模块拆到独立文件,用
mod xxx;声明,验证仍能调用. - 可见性实验:给模块里的函数去掉
pub观察可见性报错,再改成pub(crate)对比. - 单元测试:给一个函数写
#[cfg(test)] mod tests单元测试,用cargo test跑通,并验证它能调用私有函数. - use 与别名:用
use引入一个标准库类型并用as重命名,在代码中使用别名.
基础系列完成
至此走完 Rust 基础的全部地基:工具链,变量,所有权与借用,复合类型,控制流,集合与函数式,泛型与特征,错误处理与工程组织.
接下来进入**「Rust 进阶 · 生命周期与并发」**分类,正式攻克生命周期,智能指针与多线程这些 Rust 最难也最核心的部分.