MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Rust Cargo工具的基础

2022-08-084.9k 阅读

Rust Cargo工具基础概念

Cargo 是 Rust 的构建系统和包管理器,对于 Rust 开发者来说,它就如同得力助手,极大地简化了项目管理、依赖管理和构建流程。

项目初始化

使用 cargo new 命令来创建一个新的 Rust 项目。例如,要创建一个名为 hello_cargo 的新项目,可以在终端中执行以下命令:

cargo new hello_cargo

这会在当前目录下创建一个名为 hello_cargo 的目录,该目录结构如下:

hello_cargo
├── Cargo.toml
└── src
    └── main.rs

其中,Cargo.toml 文件是项目的配置文件,用于描述项目的元数据、依赖等信息。而 src/main.rs 则是项目的主要源代码文件,初始内容如下:

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

这个简单的程序会在运行时输出 “Hello, world!”。

Cargo.toml文件

Cargo.toml 遵循 TOML(Tom's Obvious, Minimal Language)格式,它是 Cargo 用来管理项目配置的核心文件。

  1. 项目元数据:在 Cargo.toml 文件开头部分,定义了项目的基本信息,如:
[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2021"

这里的 name 是项目名称,version 是项目版本号,遵循语义化版本号规范 MAJOR.MINOR.PATCHedition 则指定了 Rust 的版本。 2. 依赖管理:如果项目需要使用外部库,就可以在 Cargo.toml 中添加依赖。例如,要使用 rand 库来生成随机数,可以这样添加:

[dependencies]
rand = "0.8.5"

这里指定了 rand 库及其版本号。Cargo 会根据版本号去查找并下载相应的库及其依赖。

构建与运行项目

构建项目

使用 cargo build 命令来构建项目。在项目根目录下执行:

cargo build

Cargo 会编译项目中的 Rust 代码,并将生成的可执行文件放在 target/debug 目录下(对于开发模式)。如果项目有依赖,Cargo 会先下载并编译这些依赖。

对于发布版本,可以使用 cargo build --release 命令,生成的可执行文件会放在 target/release 目录下。发布版本会进行更多的优化,文件体积更小且运行速度更快,但编译时间通常会更长。

运行项目

构建完成后,可以使用 cargo run 命令直接运行项目。同样在项目根目录下执行:

cargo run

这会先调用 cargo build 进行构建(如果需要),然后运行生成的可执行文件。例如,对于上述 hello_cargo 项目,执行 cargo run 会输出:

Hello, world!

检查代码

语法检查

cargo check 命令用于检查项目代码的语法是否正确,但不会生成可执行文件。这在开发过程中可以快速发现语法错误,节省编译时间。例如,在 src/main.rs 中故意引入一个语法错误:

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

然后执行 cargo check,会得到如下错误提示:

error: expected one of `,`, `)`, or `;`, found `}`
 --> src/main.rs:3:1
  |
3 | }
  | ^ expected one of `,`, `)`, or `;`

通过这种方式,可以及时发现并修正代码中的语法问题。

测试

单元测试

Rust 内置了强大的测试框架,结合 Cargo 可以很方便地编写和运行单元测试。在 Rust 中,测试函数需要使用 #[test] 注解。例如,在 src/lib.rs 文件(如果项目有库部分)或者 src/main.rs 中添加如下测试代码:

fn add(a: i32, b: i32) -> i32 {
    a + b
}

#[test]
fn test_add() {
    assert_eq!(add(2, 3), 5);
}

这里定义了一个 add 函数,并编写了一个测试函数 test_add 来验证 add 函数的正确性。使用 cargo test 命令来运行测试:

cargo test

Cargo 会编译测试代码并运行所有标记为 #[test] 的函数。如果测试通过,会输出类似如下信息:

running 1 test
test test_add ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

如果测试失败,比如修改 test_add 中的断言为 assert_eq!(add(2, 3), 6);,再次运行 cargo test,会得到:

running 1 test
test test_add ... FAILED

failures:

---- test_add stdout ----
thread 'test_add' panicked at 'assertion failed: `(left == right)`
  left: `5`,
 right: `6`', src/main.rs:7:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    test_add

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

这样可以清晰地看到测试失败的原因。

集成测试

集成测试用于测试多个模块或组件之间的交互。集成测试通常放在 tests 目录下。在项目根目录创建 tests 目录,然后在其中创建一个 Rust 文件,例如 integration_test.rs。假设项目中有一个 lib.rs 文件定义了一些功能:

// src/lib.rs
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

tests/integration_test.rs 中编写集成测试:

extern crate hello_cargo;

#[test]
fn test_add_integration() {
    assert_eq!(hello_cargo::add(2, 3), 5);
}

这里通过 extern crate 引入项目的库。然后使用 cargo test 同样可以运行集成测试。Cargo 会将 tests 目录下的文件作为独立的 crate 进行编译和测试,这样可以模拟外部使用项目库的场景,更全面地测试项目功能。

文档生成

编写文档注释

Rust 支持通过文档注释来生成项目文档。有两种类型的文档注释://///!/// 用于为项(函数、结构体、模块等)添加文档注释,//! 用于为整个 crate 或模块添加文档注释。例如:

/// Adds two numbers together.
///
/// # Examples
///
/// ```
/// let result = add(2, 3);
/// assert_eq!(result, 5);
/// ```
fn add(a: i32, b: i32) -> i32 {
    a + b
}

这里的 /// 注释详细描述了 add 函数的功能,并通过 # Examples 给出了使用示例。

生成文档

使用 cargo doc 命令可以生成项目文档。执行该命令后,Cargo 会在 target/doc 目录下生成 HTML 格式的文档。可以通过浏览器打开 target/doc/<项目名称>/index.html 来查看文档。生成的文档不仅包含函数、结构体等的定义,还会包含文档注释中的内容,对于项目的使用者来说非常方便。例如,对于上述添加了文档注释的 add 函数,在生成的文档中可以清晰地看到函数的功能描述和使用示例。

管理依赖

版本约束

Cargo.toml 中指定依赖的版本时,可以使用多种版本约束方式。

  1. 具体版本号:如 rand = "0.8.5",这表示只能使用 0.8.5 版本的 rand 库。
  2. 语义化版本范围
    • ^ 前缀表示兼容版本范围。例如,rand = "^0.8.5" 表示可以使用 0.8.5 及所有不改变 MAJOR 版本号的后续版本,即 0.8.x 系列版本(x 为大于等于 5 的数字)。
    • ~ 前缀表示次要版本兼容范围。例如,rand = "~0.8.5" 表示可以使用 0.8.5 及所有不改变 MINOR 版本号的后续 PATCH 版本,即 0.8.50.8.60.8.7 等。

更新依赖

使用 cargo update 命令可以更新项目的依赖到最新的兼容版本。例如,如果在 Cargo.toml 中有依赖 rand = "^0.8.5",执行 cargo update 后,如果有新的 0.8.x 版本可用,Cargo 会更新 rand 库到最新的 0.8.x 版本。需要注意的是,cargo update 不会改变 Cargo.toml 中指定的版本约束。如果要更新到不兼容的新版本,需要手动修改 Cargo.toml 中的版本号。

锁定依赖

Cargo 会生成一个 Cargo.lock 文件,用于锁定项目依赖的具体版本。当执行 cargo buildcargo run 等命令时,Cargo 会优先使用 Cargo.lock 文件中指定的版本,以确保项目在不同环境下使用相同版本的依赖。如果删除 Cargo.lock 文件,再次执行构建相关命令时,Cargo 会根据 Cargo.toml 中的版本约束重新下载和锁定依赖。一般来说,在团队开发中,应该将 Cargo.lock 文件提交到版本控制系统,以保证团队成员使用相同版本的依赖。

多包项目

创建多包项目

Cargo 支持创建包含多个包(package)的项目,即工作区(workspace)。使用以下命令创建一个工作区:

cargo new --workspace my_workspace

这会创建一个名为 my_workspace 的目录,目录结构如下:

my_workspace
├── Cargo.toml
└── src
    └── main.rs

其中,根目录下的 Cargo.toml 文件定义了工作区的相关信息。然后可以在工作区中添加子包,例如:

cd my_workspace
cargo new my_package

这会在 my_workspace 目录下创建一个名为 my_package 的子包,my_package 目录结构与普通的 Rust 项目类似,有自己的 Cargo.tomlsrc 目录。

工作区配置

在工作区根目录的 Cargo.toml 文件中,通过 [workspace] 部分来配置工作区。例如:

[workspace]
members = [
    "my_package",
    # 可以添加更多子包路径
]

这里的 members 数组指定了工作区包含的子包路径。

构建与管理工作区

在工作区根目录执行 cargo build 命令,Cargo 会构建工作区内的所有包。同样,cargo test 会运行所有包的测试,cargo doc 会为所有包生成文档。也可以针对单个子包进行操作,例如进入 my_package 目录后执行 cargo build 只构建 my_package。工作区中的包可以相互依赖,通过在子包的 Cargo.toml 中使用相对路径来指定依赖,例如:

[dependencies]
my_other_package = { path = "../my_other_package" }

这样就建立了子包之间的依赖关系,方便在大型项目中进行模块化开发和管理。

发布项目

注册账号

要发布 Rust 项目到 crates.io(Rust 官方的包注册表),首先需要在 crates.io 上注册账号。可以通过访问 crates.io 网站进行注册。注册完成后,使用 cargo login 命令并输入在 crates.io 上获取的 API 令牌来登录:

cargo login <API 令牌>

准备发布

在发布项目之前,需要确保项目的 Cargo.toml 文件中的元数据准确无误,包括项目名称、版本号、描述等。同时,项目应该通过所有测试,并且文档要完整。

发布项目

使用 cargo publish 命令来发布项目。在项目根目录执行该命令,Cargo 会将项目上传到 crates.io。例如:

cargo publish

发布成功后,其他开发者就可以通过在 Cargo.toml 中添加依赖来使用你的项目,例如:

[dependencies]
my_project = "0.1.0"

需要注意的是,每次发布新版本时,都需要更新 Cargo.toml 中的版本号,以遵循语义化版本规范。

通过以上对 Rust Cargo 工具基础的介绍,开发者可以更加高效地进行 Rust 项目的开发、管理和发布,充分利用 Cargo 提供的各种功能来提升开发效率和项目质量。无论是小型的个人项目还是大型的团队协作项目,Cargo 都能发挥重要的作用。