包和单元箱

我们将要介绍的模块系统的第一部分是包(packages)和单元箱(crates)。

一个单元箱是 Rust 编译器在同一时间考虑的最小代码量。即使你运行 rustc 而不是 cargo 并传递一个单独的源代码文件(正如我们在第一章的“编写和运行 Rust 程序”部分所做的那样),编译器也会将该文件视为一个单元箱。单元箱可以包含模块,并且这些模块可以定义在与单元箱一起编译的其他文件中,我们将在接下来的章节中看到。

一个单元箱可以有两种形式:二进制单元箱或库单元箱。 二进制单元箱是可以编译为可执行文件的程序,你可以运行该可执行文件,例如命令行程序或服务器。每个二进制单元箱都必须有一个名为 main 的函数,该函数定义了可执行文件运行时发生的事情。到目前为止,我们创建的所有单元箱都是二进制单元箱。

库单元箱没有 main 函数,它们不会编译为可执行文件。相反,它们定义了旨在与多个项目共享的功能。例如,我们在第二章中使用的 rand 单元箱提供了生成随机数的功能。大多数情况下,当 Rustacean 说“单元箱”时,他们指的是库单元箱,并且他们将“单元箱”与“库”的一般编程概念互换使用。

单元箱根是 Rust 编译器开始的源文件,它构成了你的单元箱的根模块(我们将在“定义模块来控制作用域和隐私”章节中深入解释模块)。

是提供一组功能的一个或多个单元箱的捆绑。一个包包含一个 Cargo.toml 文件,该文件描述如何构建这些单元箱。Cargo 实际上是一个包,其中包含你一直用来构建代码的命令行工具的二进制单元箱。Cargo 包还包含一个二进制单元箱所依赖的库单元箱。其他项目可以依赖 Cargo 库单元箱来使用 Cargo 命令行工具使用的相同逻辑。一个包可以包含任意数量的二进制单元箱,但最多只能包含一个库单元箱。一个包必须至少包含一个单元箱,无论是库单元箱还是二进制单元箱。

让我们逐步了解一下当我们创建一个包时会发生什么。首先,我们输入命令 cargo new my-project

$ cargo new my-project
     Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs

在我们运行 cargo new my-project 之后,我们使用 ls 来查看 Cargo 创建的内容。在项目目录中,有一个 Cargo.toml 文件,它为我们提供了一个包。还有一个包含 main.rssrc 目录。在你的文本编辑器中打开 Cargo.toml,并注意其中没有提及 src/main.rs。Cargo 遵循一个约定,即 src/main.rs 是与包同名的二进制单元箱的单元箱根。同样,Cargo 知道如果包目录包含 src/lib.rs,则该包包含一个与包同名的库单元箱,并且 src/lib.rs 是其单元箱根。Cargo 将单元箱根文件传递给 rustc 以构建库或二进制文件。

在这里,我们有一个只包含 src/main.rs 的包,这意味着它只包含一个名为 my-project 的二进制单元箱。如果一个包包含 src/main.rssrc/lib.rs,它将有两个单元箱:一个二进制单元箱和一个库单元箱,它们的名称都与包的名称相同。一个包可以通过将文件放置在 src/bin 目录中来拥有多个二进制单元箱:每个文件都将是一个单独的二进制单元箱。