Rust 模块系统:Package、Crate 与 Module 组织
全面解析 Rust 模块系统:Package、Crate、Module、pub 访问控制与 use 关键字,构建大型工程代码结构。
当 Rust 项目规模逐渐超出单个源码文件时,良好的代码组织与作用域管理至关重要。Rust 提供了严谨的模块系统,兼顾封装性、隐私安全与可复用性。
像给 10 岁孩子解释:玩具工厂与作业部门#
把构建一个 Rust 项目想象成运营一家大型玩具工厂:
- Package (
Cargo.toml): 整个工厂园区,包含建造图纸、工具箱和采购清单。 - Crate (包 / 箱): 装满组装好的产品、可以直接交付给客户或合作伙伴的集装箱(可执行程序或共享库)。
- Module (部门): 工厂内部各个独立作业车间(如:木工车间、喷漆车间、质检部门)。
- 访问隐私 (
pub): 内部工作车间的防盗门(private)与对外开放的接待前台(pub)。Rust 默认将所有房门锁上,防止外部误入操作精密机器。
graph TD
subgraph Package ["Package (Cargo.toml)"]
subgraph BinaryCrate ["Binary Crate (src/main.rs)"]
MainFn["main() entry point"]
end
subgraph LibraryCrate ["Library Crate (src/lib.rs)"]
RootMod["Crate Root (crate::)"]
RootMod --> ModFront["mod front_of_house"]
ModFront --> ModHosting["pub mod hosting"]
ModHosting --> FnAdd["pub fn add_to_waitlist()"]
RootMod --> ModBack["mod back_of_house"]
ModBack --> FnCook["fn fix_incorrect_order()"]
end
end
MainFn -->|use restaurant::front_of_house::hosting| FnAdd
核心概念层级#
| 概念 | 定义 | 文件组织约定 |
|---|---|---|
| Package | 包含 Cargo.toml 的 Cargo 构建单元,用于构建一个或多个 Crate。 | 包含 Cargo.toml 的项目根目录 |
| Crate | 生成二进制可执行文件或库文件的模块树编译单元。 | src/main.rs (二进制) 或 src/lib.rs (库) |
| Module | 组织 Crate 内部代码结构并控制访问权限的命名空间。 | 内联 mod name { ... } 或 src/name.rs |
| Path | 引用模块树中各项内容(结构体、函数等)的定位路径。 | crate::front_of_house::hosting::add_to_waitlist() |
模块与隐私规则#
在 Rust 中,所有项(函数、方法、结构体、枚举、模块)默认对父模块完全私有(private)。
graph LR
Parent["父模块"] -->|可见子模块的所有内容| Child["子模块"]
Child -->|不可见未公开的同级项| Sibling["同级项"]
Child -->|始终可见父模块中的项| Parent
餐厅业务模块实例#
src/lib.rs
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
fn seat_at_table() {} // private: 仅在 hosting 内部可调用
}
mod serving {
fn take_order() {}
fn serve_order() {}
fn take_payment() {}
}
}
pub fn eat_at_restaurant() {
// 从 Crate 根路径出发的绝对路径
crate::front_of_house::hosting::add_to_waitlist();
// 从当前模块出发的相对路径
front_of_house::hosting::add_to_waitlist();
}rust[!NOTE] 将模块声明为
pub mod仅代表父级可以引用该模块本身。其内部的函数和字段仍为私有,必须逐个添加pub显式导出。
结构体与枚举在 pub 下的区别#
pub 在结构体和枚举中的表现有所不同:
- 结构体 (Struct): 使用
pub struct仅公开结构体类型名称,其内部字段仍默认为私有,必须逐个为公开字段添加pub。 - 枚举 (Enum): 一旦使用
pub enum,其包含的所有枚举成员(Variants)将自动全部公开。
src/lib.rs
mod back_of_house {
pub struct Breakfast {
pub toast: String, // 公开字段:顾客自选面包类型
seasonal_fruit: String, // 私有字段:主厨根据时令决定
}
impl Breakfast {
// 由于存在私有字段,必须提供一个公开的构造函数
pub fn summer(toast: &str) -> Breakfast {
Breakfast {
toast: String::from(toast),
seasonal_fruit: String::from("peaches"),
}
}
}
#[derive(Debug)]
pub enum Appetizer {
Soup, // 自动公开
Salad, // 自动公开
}
}rust使用 use 将路径引入作用域#
重复编写冗长路径会导致代码繁琐。使用 use 关键字可像创建软链接一样将路径引入当前作用域:
src/lib.rs
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
// 惯用风格:函数引入其父模块
use crate::front_of_house::hosting;
// 惯用风格:结构体/枚举直接引入类型本身
use std::collections::HashMap;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
let mut map = HashMap::new();
map.insert("table_1", "occupied");
}rustsequenceDiagram
participant Code as 调用方代码
participant Scope as 本地作用域
participant CrateTree as Crate 模块树
Note over Scope,CrateTree: use crate::front_of_house::hosting;
Scope->>CrateTree: 解析 hosting 模块路径
CrateTree-->>Scope: 在当前作用域创建 hosting 别名
Code->>Scope: hosting::add_to_waitlist()
Scope->>CrateTree: 最终调用 front_of_house::hosting::add_to_waitlist()
使用 pub use 重新导出接口#
使用 use 引入的项在当前作用域默认为私有。结合使用 pub use 可以将其对外公开,从而设计出优雅扁平的公开 API:
src/lib.rs
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
// 重新导出:外部用户可以直接调用 restaurant::hosting::add_to_waitlist()
pub use crate::front_of_house::hosting;rust将模块拆分为独立多文件#
在工程化开发中,推荐将模块映射到独立的文件与目录结构:
my_project/
├── Cargo.toml
└── src/
├── main.rs
├── lib.rs
└── front_of_house/
├── mod.rs (或 front_of_house.rs)
└── hosting.rstextsrc/lib.rs
// 声明 front_of_house 模块,Rust 会自动定位并加载 src/front_of_house.rs
pub mod front_of_house;
pub use crate::front_of_house::hosting;rustsrc/front_of_house.rs
// 声明 hosting 子模块,Rust 会自动加载 src/front_of_house/hosting.rs
pub mod hosting;rustsrc/front_of_house/hosting.rs
pub fn add_to_waitlist() {
println!("已成功添加至等候列表!");
}rust总结#
- Package 是由
Cargo.toml统一管理的 Crate 集合。 - Crate 是生成二进制或共享库的编译基本单元。
- Module (
mod) 构建树状命名空间并控制可见性。 - Rust 默认私有;使用
pub精确暴露模块、函数和字段。 - 使用
use简化调用路径,使用pub use优雅重构公开 API。