首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >19-Rust 教程 - 包管理 Cargo

19-Rust 教程 - 包管理 Cargo

作者头像
LarryLan
发布2026-05-14 18:10:14
发布2026-05-14 18:10:14
1170
举报

包管理 Cargo

Rust 的瑞士军刀:从创建项目到发布 crate

🎬 引入

你有没有经历过这样的绝望:

  1. 下载了一个库
  2. 发现需要另一个库
  3. 那个库又需要别的库
  4. 最后手动下载了十几个文件
  5. 还不知道怎么链接

在 Rust 之前,C/C++ 程序员就是这样过来的……

Rust 的 Cargo 让这一切成为了历史。今天咱们就聊聊这个让依赖管理变得如此简单的神器。

📌 核心概念

什么是 Cargo?

Cargo 是 Rust 的包管理器 + 构建系统。它负责:

  • 创建和管理项目
  • 下载和编译依赖
  • 构建和运行项目
  • 测试和发布代码

生活化类比:

想象你要做一顿大餐:

  • 没有 Cargo:自己去菜市场买菜、自己杀鸡、自己种菜……
  • 有 Cargo:打开外卖 App,点菜,等着吃

Cargo 的核心文件

文件

作用

Cargo.toml

项目配置文件(清单)

Cargo.lock

依赖锁定文件(精确版本)

src/main.rs

程序入口(可执行文件)

src/lib.rs

库入口(库项目)

Cargo 命令速查

代码语言:javascript
复制
# 创建项目
cargo new my_project      # 创建可执行文件
cargo new --lib my_lib    # 创建库

# 构建和运行
cargo build               # 编译
cargo run                 # 编译并运行
cargo check               # 快速检查(不生成二进制)

# 依赖管理
cargo add <crate>         # 添加依赖
cargo update              # 更新依赖
cargo tree                # 查看依赖树

# 测试和文档
cargo test# 运行测试
cargo doc                 # 生成文档
cargo doc --open          # 生成并打开文档

# 发布
cargo publish             # 发布到 crates.io
cargo package             # 打包检查

💻 代码示例

基础示例:创建项目

代码语言:javascript
复制
# 创建可执行文件项目
cargo new hello_world
cd hello_world

# 项目结构
hello_world/
├── Cargo.toml
└── src/
    └── main.rs

Cargo.toml 长这样:

代码语言:javascript
复制
[package]
name = "hello_world"
version = "0.1.0"
edition = "2021"

[dependencies]
# 依赖写在这里

添加依赖

方法 1:手动编辑 Cargo.toml

代码语言:javascript
复制
[package]
name = "my_app"
version = "0.1.0"
edition = "2021"

[dependencies]
serde = "1.0"           # 最新版本
serde_json = "1.0.108"  # 指定版本
reqwest = { version = "0.11", features = ["json"] }  # 带特性

方法 2:使用 cargo add(推荐)

代码语言:javascript
复制
cargo add serde
cargo add serde_json
cargo add reqwest --features json

说人话:

  • "1.0":兼容 1.0.x 的最新版本(语义化版本)
  • "1.0.108":精确版本
  • { version = "0.11", features = ["json"] }:带特性的依赖

依赖版本说明

代码语言:javascript
复制
[dependencies]
# 语义化版本(SemVer)
serde = "1.0"        # >=1.0.0, <2.0.0
serde = "1.0.0"      # >=1.0.0, <1.1.0
serde = "=1.0.108"   # 精确 1.0.108

# 其他写法
serde = ">=1.0, <2.0"   # 范围
serde = "*"             # 任何版本(不推荐!)

语义化版本规则:

  • MAJOR.MINOR.PATCH(主版本。次版本。补丁版本)
  • 1.0 → 允许 1.0.01.99.99
  • 1.0.0 → 允许 1.0.01.0.99

使用依赖

代码语言:javascript
复制
// src/main.rs
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct Person {
    name: String,
    age: u32,
}

fn main() {
    let person = Person {
        name: String::from("Alice"),
        age: ,
    };
    
    // 序列化为 JSON
    let json = serde_json::to_string(&person).unwrap();
    println!("{}", json);  // {"name":"Alice","age":30}
    
    // 反序列化
    let data = r#"{"name":"Bob","age":25}"#;
    let person: Person = serde_json::from_str(data).unwrap();
    println!("{:?}", person);
}

Workspace(多项目管理)

代码语言:javascript
复制
my_workspace/
├── Cargo.toml          # 工作区配置
├── crate_a/
│   ├── Cargo.toml
│   └── src/
├── crate_b/
│   ├── Cargo.toml
│   └── src/
└── shared/
    ├── Cargo.toml
    └── src/

工作区 Cargo.toml

代码语言:javascript
复制
[workspace]
members = [
    "crate_a",
    "crate_b",
    "shared",
]

[workspace.dependencies]
# 共享依赖(所有成员可用)
serde = "1.0"
tokio = "1.0"

成员 Cargo.toml

代码语言:javascript
复制
[package]
name = "crate_a"
version = "0.1.0"
edition = "2021"

[dependencies]
# 继承工作区的依赖
serde = { workspace = true }
shared = { path = "../shared" }  # 本地依赖

条件编译(特性)

代码语言:javascript
复制
[features]
default = ["std"]
std = []
full = ["std", "async"]
async = ["tokio"]

[dependencies]
tokio = { version = "1.0", optional = true }

使用特性:

代码语言:javascript
复制
# 使用默认特性
cargo build

# 使用特定特性
cargo build --features full

# 不使用默认特性
cargo build --no-default-features --features async

发布 crate

  1. 准备发布
代码语言:javascript
复制
# 登录 crates.io
cargo login <your_api_token>

# 打包检查
cargo package

# 发布
cargo publish
  1. Cargo.toml 必填项
代码语言:javascript
复制
[package]
name = "my_crate"
version = "0.1.0"
edition = "2021"
description = "我的超棒库"
license = "MIT"
repository = "https://github.com/username/my_crate"
documentation = "https://docs.rs/my_crate"

🐛 常见坑点

坑点 1:依赖版本冲突

代码语言:javascript
复制
# ❌ 可能冲突
[dependencies]
serde = "1.0.100"
some_crate = "0.1"  # 这个 crate 依赖 serde 1.0.200

编译器在说什么人话?

"两个依赖需要不同版本的 serde,冲突了!"

解决方案:

代码语言:javascript
复制
# 更新依赖
cargo update

# 或者统一版本
cargo add serde@1.0.200

坑点 2:忘记提交 Cargo.lock

代码语言:javascript
复制
# ❌ 只提交了 Cargo.toml
git add Cargo.toml
git commit -m "添加依赖"

# ❌ 忘了 Cargo.lock

问题:

  • 可执行文件项目:应该提交 Cargo.lock(确保构建一致)
  • 库项目:不应该提交 Cargo.lock(让使用者决定版本)

坑点 3:循环依赖

代码语言:javascript
复制
# crate_a/Cargo.toml
[dependencies]
crate_b = { path = "../crate_b" }

# crate_b/Cargo.toml
[dependencies]
crate_a = { path = "../crate_a" }  # ❌ 循环依赖!

解决方案:

  • 重构代码,提取公共部分到第三个 crate
  • 使用 trait 解耦

坑点 4:特性依赖问题

代码语言:javascript
复制
# ❌ 这样写有问题
[dependencies]
serde = { version = "1.0", features = ["derive"] }

# 其他 crate 可能也需要 serde,但没启用 derive 特性

解决方案:

确保所有需要的特性都启用了,或者用 workspace 统一管理。

坑点 5:本地路径依赖的坑

代码语言:javascript
复制
[dependencies]
my_lib = { path = "../my_lib" }

问题:

  • 发布时会失败(路径不存在)
  • 别人无法使用

正确做法:

代码语言:javascript
复制
[dependencies]
# 开发时用本地路径
my_lib = { path = "../my_lib" }

# 发布时改用 crates.io
# my_lib = "1.0"

或者用条件:

代码语言:javascript
复制
[dependencies]
my_lib = { path = "../my_lib", optional = true }

🎯 实战案例

案例 1:Web 服务项目

代码语言:javascript
复制
[package]
name = "web_server"
version = "0.1.0"
edition = "2021"

[dependencies]
# Web 框架
axum = "0.7"
tokio = { version = "1.0", features = ["full"] }

# 数据库
sqlx = { version = "0.7", features = ["runtime-tokio-native-tls", "postgres"] }

# 序列化
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

# 日志
tracing = "0.1"
tracing-subscriber = "0.3"

# 配置
dotenvy = "0.15"

案例 2:CLI 工具

代码语言:javascript
复制
[package]
name = "my_cli"
version = "0.1.0"
edition = "2021"

[[bin]]
name = "my_cli"
path = "src/main.rs"

[dependencies]
# 参数解析
clap = { version = "4.0", features = ["derive"] }

# 文件操作
walkdir = "2.3"

# 进度条
indicatif = "0.17"

# 颜色输出
colored = "2.0"

[dev-dependencies]
# 测试用
assert_cmd = "2.0"

案例 3:库项目

代码语言:javascript
复制
[package]
name = "my_library"
version = "0.1.0"
edition = "2021"
description = "一个超棒的工具库"
license = "MIT"
repository = "https://github.com/username/my_library"
documentation = "https://docs.rs/my_library"

[lib]
name = "my_lib"
path = "src/lib.rs"

[dependencies]
# 核心依赖
thiserror = "1.0"  # 错误处理

[features]
default = ["std"]
std = []
async = ["tokio"]

[dependencies.tokio]
version = "1.0"
optional = true

[dev-dependencies]
# 测试依赖
tokio = { version = "1.0", features = ["full"] }

案例 4:Workspace 管理

代码语言:javascript
复制
# 根 Cargo.toml
[workspace]
resolver = "2"  # 使用 Rust 2021 的依赖解析器
members = [
    "core",
    "api",
    "cli",
    "web",
]

[workspace.package]
version = "0.1.0"
edition = "2021"
license = "MIT"

[workspace.dependencies]
# 共享依赖
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.0", features = ["full"] }
tracing = "0.1"

🧠 思维导图

19-包管理 Cargo
19-包管理 Cargo

📝 小结

金句回顾:

  1. Cargo 是 Rust 的瑞士军刀——创建、构建、测试、发布一把梭
  2. 语义化版本——1.0 不等于 1.0.0,范围要搞清
  3. Workspace 管理多项目——共享依赖,统一版本
  4. 特性(features)——按需启用,灵活配置
  5. 发布前检查——cargo package 先打包看看

下篇预告:

代码写完了,怎么确保它是对的?测试啊!下篇聊聊Rust 的测试系统——单元测试、集成测试、文档测试,让你写出靠谱的代码!

🔗 参考资料

  • Cargo Book
  • Crates.io
  • 语义化版本
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-05-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Larry的Hub 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 包管理 Cargo
    • 🎬 引入
    • 📌 核心概念
      • 什么是 Cargo?
      • Cargo 的核心文件
      • Cargo 命令速查
    • 💻 代码示例
      • 基础示例:创建项目
      • 添加依赖
      • 依赖版本说明
      • 使用依赖
      • Workspace(多项目管理)
      • 条件编译(特性)
      • 发布 crate
    • 🐛 常见坑点
      • 坑点 1:依赖版本冲突
      • 坑点 2:忘记提交 Cargo.lock
      • 坑点 3:循环依赖
      • 坑点 4:特性依赖问题
      • 坑点 5:本地路径依赖的坑
    • 🎯 实战案例
      • 案例 1:Web 服务项目
      • 案例 2:CLI 工具
      • 案例 3:库项目
      • 案例 4:Workspace 管理
    • 🧠 思维导图
    • 📝 小结
    • 🔗 参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档