Rust 学习笔记(三)Hello, Cargo!

Hello, Cargo!

Cargo 是 Rust 的构建系统和包管理器。大多数 Rustaceans(Rust 程序员)使用这个工具来管理他们的 Rust 项目,因为 Cargo 为你处理了很多任务,比如构建你的代码、下载你的代码所依赖的库,并构建这些库。(我们把你的代码需要的库称为依赖项。)

像我们之前写的最简单的 Rust 程序,没有依赖项。如果我们用 Cargo 来构建“Hello, world!”项目,它只会使用 Cargo 中处理构建代码的部分。随着你编写更复杂的 Rust 程序,你会添加依赖项,如果你从一开始就使用 Cargo 开始一个项目,添加依赖项会更容易。

因为绝大多数 Rust 项目都使用 Cargo,所以本书的其余部分都假设你也使用 Cargo。如果你使用官方安装程序安装了 Rust(如“安装”部分所讨论的),Cargo 会随 Rust 一起安装。如果你通过其他方式安装了 Rust,可以通过在终端中输入以下命令来检查是否安装了 Cargo:

1
$ cargo --version

如果你看到了版本号,那么你已经安装了!如果你看到了错误,比如command not found,请查看你的安装方法的文档,以确定如何单独安装 Cargo。

使用 Cargo 创建项目

让我们使用 Cargo 创建一个新项目,并看看它与我们原来的“Hello, world!”项目有什么不同。回到你的projects目录(或者你决定存放代码的任何地方)。然后,在任何操作系统上,运行以下命令:

1
2
$ cargo new hello_cargo
$ cd hello_cargo

第一个命令创建了一个名为hello_cargo的新目录和项目。我们把项目命名为hello_cargo,Cargo 会在同名的目录中创建它的文件。

进入hello_cargo目录并列出文件。你会看到 Cargo 为我们生成了两个文件和一个目录:一个Cargo.toml文件和一个src目录,里面有一个main.rs文件。

它还初始化了一个新的 Git 仓库,以及一个.gitignore文件。如果你在现有的 Git 仓库中运行cargo new,则不会生成 Git 文件;你可以通过使用cargo new --vcs=git来覆盖这种行为。

注意:Git 是一个常见的版本控制系统。你可以通过使用--vcs标志来改变cargo new使用不同的版本控制系统或不使用版本控制系统。运行cargo new --help以查看可用选项。

在你选择的文本编辑器中打开Cargo.toml。它应该看起来类似于清单 1-2 中的代码。

文件名:Cargo.toml

1
2
3
4
5
6
7
8
[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2024"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

清单 1-2:由cargo new生成的Cargo.toml的内容

这个文件是用**TOML(Tom’s Obvious, Minimal Language)**格式的,这是 Cargo 的配置格式。

第一行,[package],是一个节标题,表明接下来的语句是配置一个包的。随着我们向这个文件添加更多信息,我们会添加其他节。

接下来的三行设置了 Cargo 编译你的程序所需的配置信息:名称、版本和要使用的 Rust 版本。我们将在附录 E 中讨论edition键。

最后一行,[dependencies],是开始列出你的项目依赖项的部分。在 Rust 中,代码包被称为crate。这个项目我们不需要其他 crate,但在第 2 章的第一个项目中我们会用到,所以那时我们会使用这个依赖项部分。

现在打开src/main.rs看看:

文件名:src/main.rs

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

Cargo 为你生成了一个“Hello, world!”程序,就像我们在清单 1-1 中写的那样!到目前为止,我们的项目和 Cargo 生成的项目之间的区别在于 Cargo 把代码放在了src目录中,而且我们在顶层目录有一个Cargo.toml配置文件。

Cargo 期望你的源文件位于src目录中。顶层项目目录只是用于 README 文件、许可证信息、配置文件以及任何与你的代码无关的东西。使用 Cargo 有助于你组织你的项目。每个东西都有它该在的地方,而且每个东西都在它该在的地方。

如果你开始了一个不使用 Cargo 的项目,就像我们之前做的“Hello, world!”项目一样,你可以将它转换为一个使用 Cargo 的项目。把项目代码移到src目录中,并创建一个合适的Cargo.toml文件。一个简单的方法是运行cargo init,它会自动为你创建Cargo.toml文件。

构建和运行 Cargo 项目

现在我们来看看使用 Cargo 构建和运行“Hello, world!”程序有什么不同!从你的hello_cargo目录中,通过输入以下命令来构建你的项目:

1
2
3
$ cargo build
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs

这个命令会在target/debug/hello_cargo(在 Windows 上是target\debug\hello_cargo.exe)而不是当前目录中创建一个可执行文件。因为默认构建是一个调试构建,Cargo 把二进制文件放在一个名为debug的目录中。你可以通过以下命令运行可执行文件:

1
2
$ ./target/debug/hello_cargo # or .\target\debug\hello_cargo.exe on Windows
Hello, world!

如果一切顺利,Hello, world!应该会打印到终端上。第一次运行cargo build还会导致 Cargo 在顶层创建一个新文件:Cargo.lock。这个文件跟踪你的项目中依赖项的确切版本。这个项目没有依赖项,所以文件内容比较少。你不需要手动更改这个文件;Cargo 会为你管理它的内容。

我们刚刚用cargo build构建了一个项目,并用./target/debug/hello_cargo运行了它,但我们也可以使用cargo run来编译代码,然后运行生成的可执行文件,所有这些都在一个命令中完成:

1
2
3
4
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/hello_cargo`
Hello, world!

使用cargo run比记住要运行cargo build,然后使用整个路径来运行二进制文件更方便,所以大多数开发人员使用cargo run

注意,这次我们没有看到 Cargo 正在编译hello_cargo的输出。Cargo 发现文件没有改变,所以它没有重新构建,只是运行了二进制文件。如果你修改了你的源代码,Cargo 会在运行之前重新构建项目,你会看到这样的输出:

1
2
3
4
5
$ cargo run
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.33 secs
Running `target/debug/hello_cargo`
Hello, world!

Cargo 还提供了一个名为cargo check的命令。这个命令快速检查你的代码,确保它能够编译,但不会生成可执行文件:

1
2
3
$ cargo check
Checking hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs

为什么你不需要可执行文件呢?通常,cargo checkcargo build要快得多,因为它跳过了生成可执行文件的步骤。如果你在编写代码时不断检查你的工作,使用cargo check会加快让你知道你的项目是否仍然可以编译的过程!因此,许多 Rustaceans 在编写程序时会定期运行cargo check以确保它能够编译。然后在他们准备好使用可执行文件时运行cargo build

让我们回顾一下到目前为止我们学到的关于 Cargo 的内容:

  • 我们可以使用cargo new创建一个项目。
  • 我们可以使用cargo build构建一个项目。
  • 我们可以使用cargo run一步构建并运行一个项目。
  • 我们可以使用cargo check构建一个项目而不生成二进制文件来检查错误。
  • Cargo 不是在与我们的代码相同的目录中保存构建的结果,而是将其存储在target/debug目录中。

使用 Cargo 的另一个好处是,无论你使用的是哪种操作系统,命令都是相同的。所以,从现在开始,我们将不再为 Linux 和 macOS 与 Windows 提供具体的指令。

构建用于发布的版本

当你的项目最终准备好发布时,你可以使用cargo build --release来编译它,并启用优化。这个命令会在target/release而不是target/debug中创建一个可执行文件。优化可以让你的 Rust 代码运行得更快,但开启它们会延长你的程序编译的时间。这就是为什么有两种不同的配置文件:一个用于开发,当你希望快速且频繁地重新构建时;另一个用于构建最终的程序,这个程序不会被
反复重新构建,并且会尽可能快地运行。如果你要对代码的运行时间进行基准测试,请确保运行cargo build --release,并使用target/release中的可执行文件进行基准测试。

Cargo 作为一种约定

对于简单的项目,Cargo 并没有比直接使用rustc提供太多价值,但随着你的程序变得越来越复杂,它将证明自己的价值。一旦程序增长到多个文件或需要一个依赖项时,让 Cargo 协调构建会容易得多。

尽管hello_cargo项目很简单,但它现在使用了你将在整个 Rust 职业生涯中使用的大部分真实工具。实际上,要参与任何现有项目,你可以使用以下命令通过 Git 检出代码,切换到该项目的目录,并进行构建:

1
2
3
$ git clone example.org/someproject
$ cd someproject
$ cargo build

有关 Cargo 的更多信息,请查看它的文档。

总结

你的 Rust 之旅已经取得了良好的开端!在本章中,你已经学会了如何:

  • 使用rustup安装最新稳定版本的 Rust
  • 更新到更新的 Rust 版本
  • 打开本地安装的文档
  • 使用rustc直接编写和运行“Hello, world!”程序
  • 使用 Cargo 的约定创建和运行一个新项目

现在正是构建一个更复杂的程序以熟悉阅读和编写 Rust 代码的好时机。因此,在第 2 章中,我们将构建一个猜数字游戏程序。如果你更愿意先了解 Rust 中的常见编程概念,可以先阅读第 3 章,然后再回到第 2 章。

江达小记