强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第03章:Hello, Cargo

第03章:Hello, Cargo

3.1 为什么需要 Cargo

Cargo 是 Rust 的构建系统包管理器,类似 Python 的 pip + setuptools、Node.js 的 npm、Go 的 go mod。它管理:

功能说明
项目创建生成标准项目结构
依赖管理下载、编译、更新第三方库
构建编译编译项目和依赖
测试运行运行单元测试和集成测试
文档生成从代码注释生成 HTML 文档
发布打包发布到 crates.io
工作空间管理多 crate 项目

3.2 创建项目

cargo new

# 创建二进制项目(可执行文件)
cargo new hello_cargo
cd hello_cargo

# 创建库项目(library crate)
cargo new my_lib --lib

# 在当前目录初始化项目
cargo init

# 在当前目录初始化库项目
cargo init --lib

生成的项目结构

hello_cargo/
├── Cargo.toml          # 项目清单文件
├── .gitignore          # Git 忽略文件(自动创建)
└── src/
    └── main.rs         # 程序入口文件

src/main.rs 内容

fn main() {
    println!("Hello, world!");
}

注意: cargo new 会自动初始化 Git 仓库并创建 .gitignore 文件。如果不需要,可以使用 cargo new --vcs=none


3.3 Cargo.toml 详解

默认生成的 Cargo.toml

[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2024"

[dependencies]

package 配置项

字段说明示例
name包名(在 crates.io 上的唯一标识)"hello_cargo"
version语义化版本号"0.1.0"
editionRust 版本"2024"
authors作者列表["Name <email>"]
description包描述(发布必需)"A hello world project"
license许可证"MIT"
repository源码仓库"https://github.com/..."
documentation文档链接"https://docs.rs/..."
readmeREADME 文件"README.md"
keywords关键字(最多5个)["hello", "world"]
categories分类["command-line-utilities"]
exclude排除文件["tests/*", "benches/*"]
include包含文件["src/**/*", "Cargo.toml"]
publish是否发布false
rust-version最低 Rust 版本"1.70"

完整的 Cargo.toml 示例

[package]
name = "web-server"
version = "0.2.1"
edition = "2024"
authors = ["Zhang San <[email protected]>"]
description = "A simple HTTP web server"
license = "MIT OR Apache-2.0"
repository = "https://github.com/user/web-server"
readme = "README.md"
keywords = ["http", "server", "web"]
categories = ["web-programming::http-server"]
rust-version = "1.70"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }
axum = "0.7"
tracing = "0.1"
tracing-subscriber = "0.3"

[dev-dependencies]
reqwest = { version = "0.12", features = ["json"] }
tokio-test = "0.4"

[build-dependencies]
cc = "1.0"

[profile.release]
opt-level = 3
lto = true
codegen-units = 1
strip = true

3.4 常用 Cargo 命令

构建与运行

# 编译项目(debug 模式)
cargo build

# 编译并运行
cargo run

# 仅检查代码(不生成二进制文件,比 build 快)
cargo check

# 编译 release 模式(启用优化)
cargo build --release
命令输出目录优化级别编译速度适用场景
cargo buildtarget/debug/0(无优化)开发调试
cargo build --releasetarget/release/3(最高优化)生产部署
cargo runtarget/debug/0快速测试
cargo run --releasetarget/release/3性能测试
cargo check最快代码检查

测试与文档

# 运行所有测试
cargo test

# 生成并打开文档
cargo doc --open

# 运行基准测试(nightly)
cargo bench

# 检查代码质量
cargo clippy

# 格式化代码
cargo fmt

依赖管理

# 添加依赖(Cargo 1.62+)
cargo add serde --features derive
cargo add tokio -F full

# 移除依赖
cargo remove serde

# 更新依赖
cargo update

# 查看依赖树
cargo tree

# 检查过期依赖
cargo install cargo-outdated
cargo outdated

3.5 第一个自定义程序

修改 main.rs

use std::io;

fn main() {
    println!("=== 猜数字游戏 ===");
    println!("我心里想了一个 1-100 的数字,猜猜看!");

    // 使用固定种子的伪随机数(标准库无随机数,暂用简单方法)
    let secret = 42; // 后续章节会介绍 rand crate
    let mut attempts = 0;

    loop {
        println!("\n请输入你的猜测:");

        let mut guess = String::new();
        io::stdin()
            .read_line(&mut guess)
            .expect("读取输入失败");

        // 将字符串转换为数字
        let guess: u32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => {
                println!("请输入一个有效的数字!");
                continue;
            }
        };

        attempts += 1;

        match guess.cmp(&secret) {
            std::cmp::Ordering::Less => println!("太小了!"),
            std::cmp::Ordering::Greater => println!("太大了!"),
            std::cmp::Ordering::Equal => {
                println!("🎉 猜对了!用了 {} 次尝试。", attempts);
                break;
            }
        }
    }
}

运行:

cargo run

添加第三方依赖

# Cargo.toml
[dependencies]
rand = "0.8"
use rand::Rng;
use std::io;

fn main() {
    println!("=== 猜数字游戏 ===");
    println!("我心里想了一个 1-100 的数字,猜猜看!");

    let secret = rand::thread_rng().gen_range(1..=100);
    let mut attempts = 0;

    loop {
        println!("\n请输入你的猜测:");

        let mut guess = String::new();
        io::stdin()
            .read_line(&mut guess)
            .expect("读取输入失败");

        let guess: u32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => {
                println!("请输入一个有效的数字!");
                continue;
            }
        };

        attempts += 1;

        match guess.cmp(&secret) {
            std::cmp::Ordering::Less => println!("太小了!"),
            std::cmp::Ordering::Greater => println!("太大了!"),
            std::cmp::Ordering::Equal => {
                println!("🎉 猜对了!用了 {} 次尝试。", attempts);
                break;
            }
        }
    }
}

注意: cargo run 首次运行时会自动下载并编译依赖,后续运行会使用缓存。


3.6 项目目录详解

完整的项目结构

hello_cargo/
├── Cargo.toml              # 项目清单
├── Cargo.lock              # 依赖锁定文件(自动生成)
├── src/
│   ├── main.rs             # 二进制入口点
│   ├── lib.rs              # 库入口点(可选)
│   ├── bin/                # 额外的二进制文件
│   │   └── tool.rs         # → cargo run --bin tool
│   └── other_module.rs     # 其他模块
├── tests/                  # 集成测试
│   └── integration_test.rs
├── benches/                # 基准测试
│   └── benchmark.rs
├── examples/               # 示例代码
│   └── example.rs          # → cargo run --example example
├── build.rs                # 构建脚本(可选)
└── target/                 # 构建输出(自动生成,勿手动编辑)
    ├── debug/
    └── release/

Cargo.lock

  • 二进制项目: 应提交到 Git(保证团队使用相同依赖版本)
  • 库项目: 不应提交到 Git(让使用者决定具体版本)

target 目录

子目录说明
target/debug/debug 构建输出
target/release/release 构建输出
target/doc/生成的文档
target/package/打包的 crate

3.7 多二进制文件

方法一:src/bin/ 目录

# 项目结构
my_project/
├── Cargo.toml
└── src/
    ├── main.rs         # 默认二进制
    ├── lib.rs          # 库代码(可选)
    └── bin/
        ├── server.rs   # 额外二进制
        └── client.rs   # 额外二进制
// src/bin/server.rs
fn main() {
    println!("服务器启动中...");
}
// src/bin/client.rs
fn main() {
    println!("客户端连接中...");
}
# 运行特定二进制
cargo run --bin server
cargo run --bin client

# 列出所有二进制目标
cargo run --bin

方法二:在 Cargo.toml 中声明

[[bin]]
name = "server"
path = "src/bin/server.rs"

[[bin]]
name = "client"
path = "src/bin/client.rs"

3.8 条件编译与 Features

定义 Features

# Cargo.toml
[features]
default = ["json"]
json = ["dep:serde_json"]
xml = ["dep:quick-xml"]
full = ["json", "xml", "logging"]
logging = []

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", optional = true }
quick-xml = { version = "0.31", optional = true }
// src/main.rs
fn main() {
    #[cfg(feature = "json")]
    println!("JSON 支持已启用");

    #[cfg(feature = "xml")]
    println!("XML 支持已启用");

    #[cfg(feature = "logging")]
    println!("日志功能已启用");

    #[cfg(not(any(feature = "json", feature = "xml")))]
    println!("没有启用任何数据格式支持");
}
# 使用默认 features
cargo run

# 启用特定 features
cargo run --features "json,xml"

# 不使用默认 features
cargo run --no-default-features --features "xml"

3.9 业务场景示例:微服务项目结构

目录布局

microservice/
├── Cargo.toml              # 工作空间
├── crates/
│   ├── common/             # 共享库
│   │   ├── Cargo.toml
│   │   └── src/lib.rs
│   ├── api-server/         # API 服务
│   │   ├── Cargo.toml
│   │   └── src/main.rs
│   └── worker/             # 后台任务
│       ├── Cargo.toml
│       └── src/main.rs
├── migrations/             # 数据库迁移
├── config/                 # 配置文件
└── docker/                 # Docker 配置

工作空间 Cargo.toml

[workspace]
members = [
    "crates/common",
    "crates/api-server",
    "crates/worker",
]
resolver = "2"

[workspace.dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
tracing = "0.1"

子 crate 的 Cargo.toml

# crates/api-server/Cargo.toml
[package]
name = "api-server"
version = "0.1.0"
edition = "2024"

[dependencies]
common = { path = "../common" }
tokio = { workspace = true }
serde = { workspace = true }
axum = "0.7"

3.10 本章小结

要点说明
cargo new创建新项目,自动生成标准结构
Cargo.toml项目清单,定义元数据和依赖
cargo build/run/check构建、运行和检查项目
Features条件编译,按需启用功能
Cargo.lock锁定依赖版本,二进制项目应提交到 Git
多二进制使用 src/bin/ 目录或 [[bin]] 配置
工作空间使用 [workspace] 管理多 crate 项目

扩展阅读

  1. Cargo 手册 — 官方 Cargo 文档
  2. Cargo.toml 参考 — 所有清单字段说明
  3. 语义化版本 — 语义化版本规范
  4. Crates.io 发布指南 — 如何发布 crate