# 依赖箱与包

  • Crate(依赖箱):通常指一个单独的库或可执行单元(可以翻译为“库”或“包”)。
  • Package(包):是一个包含多个 crate 的结构,通常翻译为“包”。

ps: 下文中的依赖箱指的是 crate, 而包指的是 Package,需要注意区分。

我们将介绍的模块系统的第一部分是依赖箱和包。

依赖箱是 Rust 编译器一次考虑的最小代码量。即使你运行 rustc 而不是 cargo 并传递单个源代码文件(就像我们在第 1 章的“编写和运行 Rust 程序”部分中所做的那样),编译器也会将该文件视为依赖箱。依赖箱可以包含模块,并且模块可能在使用依赖箱编译的其他文件中定义,我们将在接下来的部分中看到。

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

库依赖箱没有 main 函数,它们不会编译为可执行文件。相反,它们定义旨在与多个项目共享的功能。例如,我们在第 2 章中使用的 rand 依赖箱提供了生成随机数的功能。大多数时候,Rust 爱好者说“crate(依赖箱)”时,他们指的是库,并且他们将“crate(依赖箱)”与“库”的一般编程概念互换使用。

根依赖箱是 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.rs 的 src 目录。在文本编辑器中打开 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.rs 和 src/lib.rs,则它有两个依赖箱:一个二进制依赖箱和一个库依赖箱,两者的名称与包相同。通过将文件放在 src/bin 目录中,包可以拥有多个二进制依赖箱:每个文件都将是一个单独的二进制依赖箱。