Crate 和包(Crates and Packages)
理解 crate 和包的概念对于组织大型 Rust 项目至关重要。这些概念定义了 Rust 代码的分发和组织方式。
基本概念
Crate
Crate 是 Rust 中编译的基本单位。它是一个二进制文件或库,包含一个模块树。
- 二进制 crate:生成可执行文件,必须有
main函数 - 库 crate:提供功能给其他程序使用,没有
main函数
Package
Package 是一个或多个 crate 的集合,提供一组功能。包含一个 Cargo.toml 文件描述如何构建这些 crate。
Package 规则
一个 package 可以包含:
- 最多一个库 crate
- 任意数量的二进制 crate
- 至少包含一个 crate(库或二进制)
项目结构
基本二进制项目
my_project/
├── Cargo.toml
└── src/
└── main.rs # 二进制 crate 根
# Cargo.toml
[package]
name = "my_project"
version = "0.1.0"
edition = "2021"
基本库项目
my_library/
├── Cargo.toml
└── src/
└── lib.rs # 库 crate 根
混合项目
my_project/
├── Cargo.toml
├── src/
│ ├── main.rs # 二进制 crate 根
│ └── lib.rs # 库 crate 根
└── tests/
└── integration_test.rs
多二进制项目
my_project/
├── Cargo.toml
├── src/
│ ├── main.rs # 主二进制文件
│ ├── lib.rs # 库 crate
│ └── bin/
│ ├── server.rs # 额外的二进制文件
│ └── client.rs # 额外的二进制文件
├── examples/
│ └── example1.rs # 示例程序
└── tests/
└── integration_test.rs
Crate 根
Crate 根是 Rust 编译器开始编译的源文件,形成 crate 的根模块。
默认 crate 根
src/main.rs- 二进制 crate 根src/lib.rs- 库 crate 根src/bin/*.rs- 额外的二进制 crate
自定义 crate 根
# Cargo.toml
[package]
name = "my_project"
version = "0.1.0"
edition = "2021"
# 自定义库 crate
[lib]
name = "my_lib"
path = "src/library.rs"
# 自定义二进制 crate
[[bin]]
name = "my_app"
path = "src/application.rs"
[[bin]]
name = "server"
path = "src/server/main.rs"
库 Crate 示例
创建库
// src/lib.rs
//! # My Library
//!
//! `my_library` 是一个用于演示的库
/// 添加两个数字
///
/// # Examples
///
/// ```
/// let result = my_library::add(2, 3);
/// assert_eq!(result, 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
/// 数学运算模块
pub mod math {
/// 计算平方
pub fn square(x: i32) -> i32 {
x * x
}
/// 计算立方
pub fn cube(x: i32) -> i32 {
x * x * x
}
}
/// 用户相关功能
pub mod user {
#[derive(Debug)]
pub struct User {
pub name: String,
pub age: u32,
}
impl User {
pub fn new(name: String, age: u32) -> Self {
User { name, age }
}
pub fn greet(&self) -> String {
format!("Hello, I'm {} and I'm {} years old", self.name, self.age)
}
}
}
使用库
// src/main.rs
use my_library::{add, math, user::User};
fn main() {
// 使用库函数
let result = add(5, 3);
println!("5 + 3 = {}", result);
// 使用模块函数
let squared = math::square(4);
println!("4² = {}", squared);
// 使用结构体
let user = User::new("Alice".to_string(), 30);
println!("{}", user.greet());
}
外部依赖
添加依赖
# Cargo.toml
[dependencies]
serde = "1.0"
tokio = { version = "1.0", features = ["full"] }
reqwest = { version = "0.11", optional = true }
[dev-dependencies]
criterion = "0.5"
[build-dependencies]
cc = "1.0"
使用外部 crate
// src/lib.rs
use serde::{Serialize, Deserialize};
use std::collections::HashMap;
#[derive(Serialize, Deserialize, Debug)]
pub struct Config {
pub name: String,
pub settings: HashMap<String, String>,
}
impl Config {
pub fn new(name: String) -> Self {
Config {
name,
settings: HashMap::new(),
}
}
}
工作空间(Workspace)
工作空间允许你管理多个相关的包:
工作空间结构
my_workspace/
├── Cargo.toml # 工作空间配置
├── common/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
├── server/
│ ├── Cargo.toml
│ └── src/
│ └── main.rs
└── client/
├── Cargo.toml
└── src/
└── main.rs
工作空间配置
# 根目录 Cargo.toml
[workspace]
members = [
"common",
"server",
"client",
]
# 共享依赖版本
[workspace.dependencies]
serde = "1.0"
tokio = "1.0"
成员包配置
# server/Cargo.toml
[package]
name = "server"
version = "0.1.0"
edition = "2021"
[dependencies]
common = { path = "../common" }
serde = { workspace = true }
tokio = { workspace = true, features = ["full"] }
发布 Crate
准备发布
# Cargo.toml
[package]
name = "my_awesome_crate"
version = "0.1.0"
edition = "2021"
authors = ["Your Name <you@example.com>"]
license = "MIT OR Apache-2.0"
description = "A short description of my crate"
repository = "https://github.com/username/my_awesome_crate"
documentation = "https://docs.rs/my_awesome_crate"
homepage = "https://github.com/username/my_awesome_crate"
keywords = ["cli", "tool", "utility"]
categories = ["command-line-utilities"]
readme = "README.md"
[dependencies]
clap = "4.0"
发布命令
# 检查包
cargo check
# 运行测试
cargo test
# 生成文档
cargo doc
# 打包(不发布)
cargo package
# 发布到 crates.io
cargo publish
版本管理
语义化版本
[dependencies]
serde = "1.0" # ^1.0.0 (兼容更新)
tokio = "=1.0.0" # 精确版本
reqwest = ">=0.11.0" # 最小版本
rand = "0.8.*" # 通配符
版本范围
[dependencies]
# 插入符号要求(默认)
serde = "^1.2.3" # >=1.2.3, <2.0.0
# 波浪号要求
serde = "~1.2.3" # >=1.2.3, <1.3.0
# 通配符要求
serde = "1.*" # >=1.0.0, <2.0.0
# 比较要求
serde = ">= 1.2.0, < 1.5.0"
特性(Features)
定义特性
# Cargo.toml
[features]
default = ["json"]
json = ["serde_json"]
xml = ["serde_xml"]
full = ["json", "xml", "compression"]
compression = ["flate2"]
[dependencies]
serde_json = { version = "1.0", optional = true }
serde_xml = { version = "0.4", optional = true }
flate2 = { version = "1.0", optional = true }
条件编译
// src/lib.rs
#[cfg(feature = "json")]
pub mod json {
use serde_json;
pub fn parse_json(data: &str) -> serde_json::Result<serde_json::Value> {
serde_json::from_str(data)
}
}
#[cfg(feature = "xml")]
pub mod xml {
// XML 处理代码
}
#[cfg(all(feature = "json", feature = "xml"))]
pub mod converter {
// JSON 和 XML 转换代码
}
使用特性
# 使用默认特性
cargo build
# 禁用默认特性
cargo build --no-default-features
# 启用特定特性
cargo build --features json,xml
# 启用所有特性
cargo build --all-features
最佳实践
1. 合理的项目结构
my_project/
├── Cargo.toml
├── README.md
├── LICENSE
├── src/
│ ├── lib.rs # 库入口
│ ├── main.rs # 二进制入口
│ ├── models/ # 数据模型
│ ├── handlers/ # 业务逻辑
│ └── utils/ # 工具函数
├── tests/ # 集成测试
├── examples/ # 示例代码
└── benches/ # 性能测试
2. 清晰的 API 设计
// 重新导出重要类型
pub use crate::models::{User, Post};
pub use crate::errors::MyError;
// 提供便利函数
pub fn quick_start() -> Result<(), MyError> {
// 简化常见用例
Ok(())
}
3. 文档和示例
//! # My Crate
//!
//! 这个 crate 提供了...
//!
//! ## 快速开始
//!
//! ```
//! use my_crate::quick_start;
//!
//! quick_start().unwrap();
//! ```
/// 这个函数做什么...
///
/// # Examples
///
/// ```
/// use my_crate::my_function;
///
/// let result = my_function(42);
/// assert_eq!(result, 84);
/// ```
pub fn my_function(x: i32) -> i32 {
x * 2
}
理解 crate 和包的概念是掌握 Rust 项目组织的关键。下一节我们将学习工作空间的高级用法。