pub)在 Rust 中,Package(包)、Crate(单元) 和 Module(模块) 是组织代码的三个核心概念。理解它们的关系对编写清晰、可维护的 Rust 项目至关重要。
| 概念 | 定义 | 说明 |
|---|---|---|
| Crate | 编译的基本单元 | 一个 crate 可以是一个 库(lib) 或 可执行程序(bin)。编译器每次只编译一个 crate。 |
| Package | 一个或多个 crate 的集合 + Cargo.toml | 一个 package 必须包含 1 个 Cargo.toml,最多包含 1 个 lib crate,可包含多个 bin crate。 |
| Module | crate 内部的命名空间和作用域 | 用于组织代码、控制可见性(pub),可嵌套。 |
✅ 一句话总结:
一个 Package 包含一个或多个 Crates;一个 Crate 由 Modules 组成。
cargo new my-project # 默认创建 bin package
cargo new --lib my-lib # 创建 lib package
Cargo.toml 决定 package 类型Bin package(可执行):
[package]
name = "my-app"
version = "0.1.0"
[[bin]]
name = "my-app" # 对应 src/main.rs
Lib package(库):
[package]
name = "my-lib"
version = "0.1.0"
[lib]
name = "my_lib" # 对应 src/lib.rs
同时包含 lib 和 bin(常见于 CLI 工具库):
my-package/
├── Cargo.toml
├── src/
│ ├── lib.rs ← lib crate
│ └── main.rs ← bin crate (name = package name)
└── src/bin/ ← 额外的可执行文件
└── tool2.rs
🔸 一个 package 只能有一个 lib crate,但可以有多个 bin crate。
每个 crate 有独立的根(root):
src/lib.rssrc/main.rs 或 src/bin/*.rscrate 是编译和链接的最小单位
当你 cargo build,Rust 会为每个 crate 生成一个 .rlib 或可执行文件。
外部依赖也是 crate
例如 serde、tokio 都是独立的 crates,通过 Cargo.toml 引入。
Module 用于 组织代码结构 和 控制访问权限。
// src/lib.rs 或 main.rs
mod network {
pub fn connect() {
println!("Connecting...");
}
fn private_helper() {} // 默认私有
}
fn main() {
network::connect(); // ✅ 可访问 pub 函数
// network::private_helper(); // ❌ 编译错误
}
// src/network.rs
pub fn connect() { ... }
在 lib.rs 或 main.rs 中声明:
mod network; // 自动加载 src/network.rs
src/
├── lib.rs
└── network/
├── mod.rs ← 模块根
├── tcp.rs
└── udp.rs
src/lib.rs:
mod network;
src/network/mod.rs:
pub mod tcp;
pub mod udp;
💡 从 Rust 2018 起,也可以不用
mod.rs,直接用network.rs+network/tcp.rs,但传统方式更清晰。
pub)| 语法 | 含义 |
|---|---|
fn foo() | 私有(仅当前模块及子模块可访问) |
pub fn foo() | 公开(任何地方可访问) |
pub(crate) fn foo() | 在当前 crate 内公开 |
pub(super) fn foo() | 对父模块公开 |
pub(in path) fn foo() | 在指定路径内公开 |
示例:
mod outer {
pub mod inner {
pub(super) fn visible_to_outer() {}
pub fn visible_everywhere() {}
}
}
// outer::inner::visible_everywhere() ✅
// outer::inner::visible_to_outer() ✅(因为 outer 是 super)
// inner::visible_to_outer() ❌(不在 outer 内)
在 Cargo.toml 添加依赖:
[dependencies]
serde = "1.0"
rand = "0.8"
在代码中引入:
use serde::{Serialize, Deserialize};
use rand::Rng;
#[derive(Serialize)]
struct Point { x: i32, y: i32 }
外部 crate 默认以 crate 名作为根模块名(如
serde、rand)。
my-cli/
├── Cargo.toml
├── src/
│ ├── main.rs // bin crate root
│ ├── lib.rs // lib crate root
│ └── commands/
│ ├── mod.rs
│ ├── start.rs
│ └── stop.rs
Cargo.toml:
[package]
name = "my-cli"
version = "0.1.0"
[[bin]]
name = "my-cli"
path = "src/main.rs"
[lib]
name = "my_cli"
path = "src/lib.rs"
src/lib.rs:
pub mod commands;
src/commands/mod.rs:
pub mod start;
pub mod stop;
src/main.rs:
use my_cli::commands;
fn main() {
commands::start::run();
}
| 概念 | 关键点 |
|---|---|
| Package | 由 Cargo.toml 定义,包含 0 或 1 个 lib crate + 任意数量 bin crate |
| Crate | 编译单元,lib 或 bin,是外部依赖的基本单位 |
| Module | crate 内部的代码组织单元,控制作用域和可见性 |
| 文件映射 | mod foo; → foo.rs 或 foo/mod.rs |
| 可见性 | 默认私有,用 pub 控制公开范围 |
如果你正在设计一个库或 CLI 工具,建议:
src/lib.rs 及其子模块src/main.rs,调用 lib 中的逻辑pub use 重导出简化 API需要我帮你设计具体项目的模块结构吗?