
在掌握了函数和模块之后,我们需要理解Rust的项目组织层级:包(Package)和Crate。这是构建大型项目的关键,理解它们的关系将帮助您更好地组织代码、管理依赖和创建可复用的库。
Rust的包系统包括:
本文将全面介绍Rust的包和Crate系统,包括:
通过本文的学习,你将能够:
**Package(包)**是一个包含 Cargo.toml 文件的目录,用于描述如何构建一个或多个Crate。
my_package/
├── Cargo.toml # 包的配置文件
└── src/
├── main.rs # 二进制Crate的入口(可选)
└── lib.rs # 库Crate的入口(可选)Package的特点:
Cargo.toml 文件**Crate(箱)**是Rust的编译单元,可以编译成库或可执行文件。
两种类型的Crate:
main 函数作为入口src/main.rs.rlib)src/lib.rsPackage(包)
├── Library Crate(库,最多一个)
│ └── src/lib.rs
├── Binary Crate 1(二进制)
│ └── src/main.rs
├── Binary Crate 2(二进制)
│ └── src/bin/binary2.rs
└── Binary Crate 3(二进制)
└── src/bin/binary3.rs规则:
src/main.rs,则是一个二进制Packagesrc/lib.rs,则可以创建库和其他二进制文件# 创建新的二进制项目
cargo new my_binary_project
# 项目结构
my_binary_project/
├── Cargo.toml
└── src/
└── main.rsCargo.toml:
[package]
name = "my_binary_project"
version = "0.1.0"
edition = "2021"
[dependencies]src/main.rs:
fn main() {
println!("Hello, World!");
}# 创建新的库项目
cargo new --lib my_library
# 项目结构
my_library/
├── Cargo.toml
└── src/
└── lib.rsCargo.toml:
[package]
name = "my_library"
version = "0.1.0"
edition = "2021"src/lib.rs:
pub fn add(x: i32, y: i32) -> i32 {
x + y
}
pub fn multiply(x: i32, y: i32) -> i32 {
x * y
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2, 3), 5);
}
}main.rs
// 方式1:使用 use 导入函数(推荐)
use my_library::{add, multiply};
fn main() {
println!("=== 调用 lib.rs 中的函数 ===\n");
// 使用导入的函数进行计算
let sum = add(10, 20);
let product = multiply(5, 6);
println!("10 + 20 = {}", sum);
println!("5 × 6 = {}", product);
// 更多示例
println!("\n更多计算:");
println!("{} + {} = {}", 15, 25, add(15, 25));
println!("{} × {} = {}", 7, 8, multiply(7, 8));
// 方式2:使用完整路径(不需要 use)
println!("\n使用完整路径调用:");
println!("100 + 200 = {}", my_library::add(100, 200));
println!("9 × 9 = {}", my_library::multiply(9, 9));
}
# 创建新项目
cargo new my_project
# 项目结构
my_project/
├── Cargo.toml
└── src/
├── lib.rs # 手动创建
└── main.rs # 已存在src/lib.rs:
pub fn greet(name: &str) {
println!("Hello, {}!", name);
}
pub fn calculate(x: i32, y: i32) -> i32 {
x + y
}src/main.rs:
use my_project::greet;
fn main() {
greet("World");
println!("结果: {}", my_project::calculate(10, 20));
}可以在 src/bin/ 目录下创建多个二进制文件:
my_project/
├── Cargo.toml
└── src/
├── lib.rs
├── main.rs
└── bin/
├── server.rs
└── client.rssrc/bin/server.rs:
fn main() {
println!("服务器启动");
}src/bin/client.rs:
fn main() {
println!("客户端启动");
}运行不同的二进制文件:
cargo run # 运行 main.rs
cargo run --bin server # 运行 server.rs
cargo run --bin client # 运行 client.rs[package]
name = "my_project" # 项目名称(必须)
version = "0.1.0" # 版本号(必须)
edition = "2021" # Rust版本(必须:2015, 2018, 2021)
authors = ["Your Name <you@example.com>"] # 作者(可选)
description = "项目描述" # 描述(可选)
license = "MIT" # 许可证(可选)
readme = "README.md" # README文件(可选)
repository = "https://github.com/user/repo" # 仓库地址(可选)
homepage = "https://example.com" # 主页(可选)[dependencies]
# 从 crates.io 添加依赖
serde = "1.0"
tokio = { version = "1.0", features = ["full"] }
# 从 Git 添加依赖
my_crate = { git = "https://github.com/user/repo" }
# 从本地路径添加依赖
local_crate = { path = "../local_crate" }
# 指定版本范围
rand = "0.8" # 版本 >=0.8.0 且 <0.9.0
json = "^1.2.3" # 版本 >=1.2.3 且 <2.0.0
http = "~1.2.3" # 版本 >=1.2.3 且 <1.3.0
log = "1.0.0" # 精确版本
# 开发依赖(只在测试时使用)
[dev-dependencies]
proptest = "1.0"
# 构建依赖(在构建脚本中使用)
[build-dependencies]
cc = "1.0"[dependencies]
my_crate = { version = "1.0", features = ["async", "tls"] }
# 定义自己的features
[features]
default = ["std"] # 默认启用哪些features
std = [] # 名为"std"的feature
async = ["tokio"]
tls = ["rustls"]使用features:
#[cfg(feature = "async")]
pub mod async_impl;
#[cfg(feature = "tls")]
pub mod tls_impl;[package]
name = "calculator"
version = "0.1.0"
edition = "2021"
authors = ["Your Name"]
description = "一个简单的计算器库"
license = "MIT OR Apache-2.0"
readme = "README.md"
repository = "https://github.com/user/calculator"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
[dev-dependencies]
criterion = "0.4"
[features]
default = ["std"]
std = []
advanced = []
[[bin]]
name = "calc"
path = "src/bin/calc.rs"
[[bin]]
name = "calc_cli"
path = "src/bin/cli.rs"在 Cargo.toml 中添加依赖:
[dependencies]
rand = "0.8"
serde = { version = "1.0", features = ["derive"] }// src/main.rs
use rand::Rng;
fn main() {
let mut rng = rand::thread_rng();
let number = rng.gen_range(1..=100);
println!("随机数: {}", number);
}use rand::Rng;
use rand::distributions::{Distribution, Uniform};
fn main() {
let mut rng = rand::thread_rng();
let die = Uniform::from(1..7);
let roll = die.sample(&mut rng);
println!("骰子: {}", roll);
}cargo new --lib math_utilssrc/lib.rs:
//! # Math Utilities
//!
//! 提供各种数学计算功能
/// 计算两个数的和
pub fn add(x: f64, y: f64) -> f64 {
x + y
}
/// 计算两个数的差
pub fn subtract(x: f64, y: f64) -> f64 {
x - y
}
/// 计算两个数的积
pub fn multiply(x: f64, y: f64) -> f64 {
x * y
}
/// 计算两个数的商
///
/// # 参数
///
/// * `x` - 被除数
/// * `y` - 除数
///
/// # 返回
///
/// 返回 `Some(结果)` 如果除数不为0,否则返回 `None`
///
/// # 示例
///
/// ```
/// use math_utils::divide;
///
/// assert_eq!(divide(10.0, 2.0), Some(5.0));
/// assert_eq!(divide(10.0, 0.0), None);
/// ```
pub fn divide(x: f64, y: f64) -> Option<f64> {
if y != 0.0 {
Some(x / y)
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2.0, 3.0), 5.0);
}
#[test]
fn test_divide() {
assert_eq!(divide(10.0, 2.0), Some(5.0));
assert_eq!(divide(10.0, 0.0), None);
}
}方式1:本地路径依赖
# 在另一个项目的 Cargo.toml 中
[dependencies]
math_utils = { path = "../math_utils" }使用库:
use math_utils::{add, multiply};
fn main() {
println!("{}", add(10.0, 20.0));
println!("{}", multiply(3.0, 4.0));
}方式2:Git依赖
[dependencies]
math_utils = { git = "https://github.com/user/math_utils" }方式3:发布到crates.io
# 发布库到crates.io
cargo publish然后使用:
[dependencies]
math_utils = "0.1.0"工作空间允许在一个大项目中管理多个相关的包:
workspace/
├── Cargo.toml # 工作空间配置
├── binary_project/
│ ├── Cargo.toml
│ └── src/
│ └── main.rs
├── library_project/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
└── shared_utils/
├── Cargo.toml
└── src/
└── lib.rs根目录 Cargo.toml:
[workspace]
members = [
"binary_project",
"library_project",
"shared_utils",
]
[workspace.package]
version = "0.1.0"
edition = "2021"成员项目的 Cargo.toml(简化):
[package]
name = "binary_project"
version.workspace = true # 使用工作空间的版本
edition.workspace = true # 使用工作空间的版本
[dependencies]
library_project = { path = "../library_project" }
shared_utils = { path = "../shared_utils" }共享依赖:
# 工作空间根目录 Cargo.toml
[workspace]
members = ["project1", "project2"]
[workspace.dependencies]
serde = "1.0"
tokio = { version = "1.0", features = ["full"] }成员项目使用共享依赖:
[package]
name = "project1"
[dependencies]
serde.workspace = true
tokio.workspace = true项目结构:
calculator_workspace/
├── Cargo.toml
├── calculator_lib/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
├── calculator_cli/
│ ├── Cargo.toml
│ └── src/
│ └── main.rs
└── calculator_web/
├── Cargo.toml
└── src/
└── lib.rscalculator_lib/src/lib.rs:
pub mod basic;
pub mod advanced;
pub use basic::{add, subtract};
pub use advanced::{power, sqrt};calculator_cli/src/main.rs:
use calculator_lib::{add, multiply, power};
fn main() {
println!("10 + 5 = {}", add(10.0, 5.0));
println!("2^3 = {}", power(2.0, 3));
}每个Crate都有一个根模块:
src/main.rs 是根src/lib.rs 是根Crate根 (lib.rs 或 main.rs)
├── 模块1
│ ├── 函数
│ └── 子模块
├── 模块2
└── 模块3示例:
// src/lib.rs (Crate根)
pub mod math {
pub mod basic {
pub fn add(x: i32, y: i32) -> i32 {
x + y
}
}
pub mod advanced {
pub fn factorial(n: u32) -> u64 {
if n <= 1 {
1
} else {
n as u64 * factorial(n - 1)
}
}
}
}
// 重新导出
pub use math::basic::add;
pub use math::advanced::factorial;src/
├── lib.rs
├── math/
│ ├── mod.rs # math模块的入口
│ ├── basic.rs # basic子模块
│ └── advanced.rs # advanced子模块src/lib.rs:
pub mod math;src/math/mod.rs:
pub mod basic;
pub mod advanced;src/math/basic.rs:
pub fn add(x: i32, y: i32) -> i32 {
x + y
}[package]
name = "my_crate" # 必须唯一
version = "0.1.0"
edition = "2021"
# 必需的元数据
authors = ["Your Name <you@example.com>"]
description = "库的简短描述"
license = "MIT OR Apache-2.0"
repository = "https://github.com/user/repo"
homepage = "https://example.com"
documentation = "https://docs.rs/my_crate"
keywords = ["keyword1", "keyword2"]
categories = ["category1", "category2"]/// 计算两个数的和
///
/// # 参数
///
/// * `a` - 第一个数
/// * `b` - 第二个数
///
/// # 返回
///
/// 返回两个数的和
///
/// # 示例
///
/// ```
/// use my_crate::add;
///
/// assert_eq!(add(2, 3), 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
a + b
}# 1. 登录crates.io
cargo login <your_api_token>
# 2. 检查包
cargo package
# 3. 发布
cargo publish遵循语义化版本(SemVer):
project/
├── Cargo.toml
├── README.md
├── LICENSE
├── src/
│ ├── lib.rs # 库入口
│ ├── main.rs # 二进制入口
│ ├── bin/ # 其他二进制文件
│ │ └── tool.rs
│ └── modules/ # 模块目录
│ ├── mod.rs
│ └── module1.rs
├── tests/ # 集成测试
│ └── integration_test.rs
└── examples/ # 示例代码
└── example1.rs# ✅ 好:指定版本范围
[dependencies]
serde = "1.0" # 允许补丁和次版本更新
# ✅ 好:锁定主版本
tokio = "1.0" # 允许1.x的任何版本
# ⚠️ 谨慎:精确版本(避免)
# serde = "1.0.0" # 不会自动更新
# ✅ 好:使用工作空间管理共享依赖
[workspace.dependencies]
common_dep = "1.0"// ✅ 好:公开API清晰
pub fn public_api() {}
// ✅ 好:内部实现私有
fn internal_helper() {}
// ✅ 好:模块内部公开
pub(crate) fn crate_internal() {}//! # Crate级别的文档
//!
//! 这个库提供...
/// 函数级别的文档
///
/// ## 使用示例
///
/// ```
/// use my_crate::function;
/// function();
/// ```
pub fn function() {}string_utils/
├── Cargo.toml
├── README.md
├── LICENSE
├── src/
│ ├── lib.rs
│ ├── formatting.rs
│ ├── validation.rs
│ └── transformation.rs
├── tests/
│ └── integration_test.rs
└── examples/
└── basic_usage.rsCargo.toml:
[package]
name = "string_utils"
version = "0.1.0"
edition = "2021"
authors = ["Your Name"]
description = "字符串工具库"
license = "MIT"
[dependencies]
[dev-dependencies]src/lib.rs:
//! # String Utils
//!
//! 提供各种字符串处理功能
pub mod formatting;
pub mod validation;
pub mod transformation;
pub use formatting::{reverse, capitalize, to_snake_case};
pub use validation::{is_email, is_phone, is_url};
pub use transformation::{trim_all, replace_all};src/formatting.rs:
/// 反转字符串
pub fn reverse(s: &str) -> String {
s.chars().rev().collect()
}
/// 首字母大写
pub fn capitalize(s: &str) -> String {
let mut chars: Vec<char> = s.chars().collect();
if !chars.is_empty() {
chars[0] = chars[0].to_uppercase().next().unwrap();
}
chars.into_iter().collect()
}
/// 转换为蛇形命名
pub fn to_snake_case(s: &str) -> String {
s.chars()
.map(|c| if c.is_uppercase() {
format!("_{}", c.to_lowercase())
} else {
c.to_string()
})
.collect()
}src/validation.rs:
/// 验证邮箱格式
pub fn is_email(email: &str) -> bool {
email.contains('@') && email.contains('.')
}
/// 验证电话号码
pub fn is_phone(phone: &str) -> bool {
phone.chars().all(|c| c.is_numeric()) && phone.len() >= 10
}
/// 验证URL
pub fn is_url(url: &str) -> bool {
url.starts_with("http://") || url.starts_with("https://")
}tests/integration_test.rs:
use string_utils::{reverse, is_email, capitalize};
#[test]
fn test_reverse() {
assert_eq!(reverse("hello"), "olleh");
}
#[test]
fn test_is_email() {
assert!(is_email("test@example.com"));
assert!(!is_email("invalid"));
}
#[test]
fn test_capitalize() {
assert_eq!(capitalize("hello"), "Hello");
}// 错误:未添加依赖
use some_crate::function; // 编译错误!解决:在Cargo.toml中添加依赖
[dependencies]
some_crate = "1.0"// 在库中
mod internal {
fn function() {}
}
// 在其他项目中使用
use my_crate::internal::function; // 错误!解决:使用pub关键字
pub mod internal {
pub fn function() {}
}# 错误:成员路径不正确
[workspace]
members = ["project"] # 如果project不存在,会失败解决:确保所有成员都存在且包含Cargo.toml
创建一个数学库,包含基础运算、统计、几何等功能,并发布。
创建一个工作空间,包含库、CLI工具和Web服务三个项目。
创建一个项目,演示如何管理不同来源的依赖(crates.io、Git、本地路径)。
创建一个库,演示版本管理和发布流程。
Workspace(工作空间)
└── Package(包)
├── Library Crate(库,可选)
├── Binary Crate 1(main.rs)
└── Binary Crate N(bin/*.rs)
└── Modules(模块)掌握了包和Crate系统后,你将能够:
接下来我们将学习: