跳到主要内容

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 项目组织的关键。下一节我们将学习工作空间的高级用法。