Skip to content

Crate 与模块

学习内容: mod 和 use vs import、可见性(pub)vs Python 的约定式私有、 Cargo.toml vs pyproject.toml、crates.io vs PyPI,以及工作空间 vs 单体仓库。

难度: 🟢 初级

myproject/
# Python — 文件是模块,带 __init__.py 的目录是包
# ├── __init__.py # 使其成为包
# ├── main.py
# ├── utils/
# │ ├── __init__.py # 使 utils 成为子包
# │ ├── helpers.py
# │ └── validators.py
# └── models/
# ├── __init__.py
# ├── user.py
# └── product.py
# 导入方式:
from myproject.utils.helpers import format_name
from myproject.models.user import User
import myproject.utils.validators as validators
src/
// Rust — mod 声明创建模块树,文件提供内容
// ├── main.rs # Crate 根 — 声明模块
// ├── utils/
// │ ├── mod.rs # 模块声明(类似 __init__.py)
// │ ├── helpers.rs
// │ └── validators.rs
// └── models/
// ├── mod.rs
// ├── user.rs
// └── product.rs
// 在 src/main.rs 中:
mod utils; # 告诉 Rust 查找 src/utils/mod.rs
mod models; # 告诉 Rust 查找 src/models/mod.rs
use utils::helpers::format_name;
use models::user::User;
// 在 src/utils/mod.rs 中:
pub mod helpers; # 声明并重新导出 helpers.rs
pub mod validators; # 声明并重新导出 validators.rs
graph TD
A["main.rs<br/>(crate root)"] --> B["mod utils"]
A --> C["mod models"]
B --> D["utils/mod.rs"]
D --> E["helpers.rs"]
D --> F["validators.rs"]
C --> G["models/mod.rs"]
G --> H["user.rs"]
G --> I["product.rs"]
style A fill:#d4edda,stroke:#28a745
style D fill:#fff3cd,stroke:#ffc107
style G fill:#fff3cd,stroke:#ffc107

Python 等价物:把 mod.rs 想象成 __init__.py——它声明模块导出什么。 Crate 根(main.rs / lib.rs)类似于顶层包的 __init__.py。

概念PythonRust
模块 = 文件自动必须用 mod 声明
包 = 目录__init__.pymod.rs
默认公开所有默认私有
设为公开_前缀 约定pub 关键字
导入语法from x import yuse x::y;
通配符导入from x import *use x::*;(不推荐)
相对导入from . import siblinguse super::sibling;
重新导出__all__ 或显式pub use inner::Thing;
# Python — "我们都是成年人"
class User:
def __init__(self):
self.name = "Alice" # 公开(按约定)
self._age = 30 # "私有"(约定:单下划线)
self.__secret = "shhh" # 名称修饰(不是真的私有)
# 没什么能阻止你访问 _age 或甚至 __secret
print(user._age) # 正常工作
print(user._User__secret) # 也能工作(名称修饰)
// Rust — 私有由编译器强制
pub struct User {
pub name: String, // 公开 — 任何人都可访问
age: i32, // 私有 — 只有这个模块能访问
}
impl User {
pub fn new(name: &str, age: i32) -> Self {
User { name: name.to_string(), age }
}
pub fn age(&self) -> i32 { // 公开 getter
self.age
}
fn validate(&self) -> bool { // 私有方法
self.age > 0
}
}
// 模块外:
let user = User::new("Alice", 30);
println!("{}", user.name); // 公开字段 — 可以
// println!("{}", user.age); // 编译错误:字段是私有的
println!("{}", user.age()); // 公开方法(getter)— 可以

Terminal window
# Python
pip install requests # 从 PyPI 安装
pip install "requests>=2.28" # 版本约束
pip freeze > requirements.txt # 锁定版本
pip install -r requirements.txt # 复现环境
Terminal window
# Rust
cargo add reqwest # 从 crates.io 安装(添加到 Cargo.toml)
cargo add reqwest@0.12 # 版本约束
# Cargo.lock 自动生成 — 无需手动步骤
cargo build # 下载并编译依赖
# Rust — Cargo.toml
[package]
name = "my-project"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { version = "1.0", features = ["derive"] } # 带特性标志
reqwest = { version = "0.12", features = ["json"] }
tokio = { version = "1", features = ["full"] }
log = "0.4"
[dev-dependencies]
mockall = "0.13"
Python 库Rust Crate用途
requestsreqwestHTTP 客户端
json (stdlib)serde_jsonJSON 解析
pydanticserde序列化/验证
pathlibstd::path (stdlib)路径处理
os / shutilstd::fs (stdlib)文件操作
reregex正则表达式
loggingtracing / log日志
click / argparseclapCLI 参数解析
asynciotokio异步运行时
datetimechrono日期和时间
pytest内置 + rstest测试
dataclasses#[derive(...)]数据结构
typing.ProtocolTrait结构化类型
subprocessstd::process (stdlib)运行外部命令
sqlite3rusqliteSQLite
sqlalchemydiesel / sqlxORM / SQL 工具包
fastapiaxum / actix-webWeb 框架

# Python 单体仓库(各种方案,无标准)
myproject/
├── pyproject.toml # 根项目
├── packages/
│ ├── core/
│ │ ├── pyproject.toml # 每个包有自己的配置
│ │ └── src/core/...
│ ├── api/
│ │ ├── pyproject.toml
│ │ └── src/api/...
│ └── cli/
│ ├── pyproject.toml
│ └── src/cli/...
# 工具:poetry workspaces、pip -e .、uv workspaces — 无标准
# Rust — 根目录的 Cargo.toml
[workspace]
members = [
"core",
"api",
"cli",
]
# 跨工作空间共享依赖
[workspace.dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
# Rust 工作空间结构 — 标准化,内置在 Cargo 中
myproject/
├── Cargo.toml # 工作空间根目录
├── Cargo.lock # 所有 crate 的单一锁文件
├── core/
│ ├── Cargo.toml # [dependencies] serde.workspace = true
│ └── src/lib.rs
├── api/
│ ├── Cargo.toml
│ └── src/lib.rs
└── cli/
├── Cargo.toml
└── src/main.rs
Terminal window
# 工作空间命令
cargo build # 构建一切
cargo test # 测试一切
cargo build -p core # 只构建 core crate
cargo test -p api # 只测试 api crate
cargo clippy --all # 检查一切

核心洞见:Rust 工作空间是一等公民,内置在 Cargo 中。 Python 单体仓库需要第三方工具(poetry、uv、pants),支持程度各异。 在 Rust 工作空间中,所有 crate 共享一个 Cargo.lock,确保项目范围内的依赖版本一致。


练习:模块可见性(点击展开)

挑战:给定以下模块结构,预测哪些行能编译,哪些不能:

mod kitchen {
fn secret_recipe() -> &'static str { "42 spices" }
pub fn menu() -> &'static str { "Today's special" }
pub mod staff {
pub fn cook() -> String {
format!("Cooking with {}", super::secret_recipe())
}
}
}
fn main() {
println!("{}", kitchen::menu()); // A 行
println!("{}", kitchen::secret_recipe()); // B 行
println!("{}", kitchen::staff::cook()); // C 行
}
答案
  • A 行:能编译 — menu() 是 pub
  • B 行:编译错误 — secret_recipe() 对 kitchen 是私有的
  • C 行:能编译 — staff::cook() 是 pub,且 cook() 可以通过 super:: 访问 secret_recipe()(子模块可以访问父模块的私有项)

关键收获:在 Rust 中,子模块可以看到父模块的私有项(类似 Python 的 _private 约定,但强制执行)。 外部人员不能。这与 Python 相反,Python 的 _private 只是一个提示。