包和库
我们将要介绍的模块系统的第一个部分是包和库。
一个 crate 是 Rust 编译器每次考虑的最小代码量。即使你运行 rustc
而不是 cargo
并传递一个源代码文件(就像我们在第 1 章“编写和运行 Rust 程序”部分所做的那样),编译器也会将该文件视为一个 crate。crate 可以包含模块,这些模块可能定义在其他文件中,并与 crate 一起编译,我们将在接下来的部分中看到。
一个crate可以有两种形式之一:二进制crate或库crate。二进制crate是可以编译成可执行文件的程序,例如命令行程序或服务器。每个二进制crate都必须有一个名为main
的函数,该函数定义了可执行文件运行时的行为。到目前为止,我们创建的所有crate都是二进制crate。
库crate 没有 main
函数,也不会编译成可执行文件。相反,它们定义了旨在与多个项目共享的功能。例如,我们在 第 2 章 中使用的 rand
crate 提供了生成随机数的功能。大多数情况下,当 Rustaceans 说“crate”时,他们指的是库crate,并且他们将“crate”与编程中的一般“库”概念互换使用。
crate root 是 Rust 编译器开始的源文件,并构成你的 crate 的根模块(我们将在 “定义模块以控制作用域和私有性” 部分详细解释模块)。
一个包是一组一个或多个提供一组功能的包。一个包包含一个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 文件,为我们提供了一个包。还有一个 src 目录,其中包含 main.rs。在文本编辑器中打开 Cargo.toml,请注意其中没有提到 src/main.rs。Cargo 遵循一个约定,即 src/main.rs 是与包同名的二进制包的包根。同样,如果包目录包含 src/lib.rs,Cargo 会知道该包包含一个与包同名的库包,而 src/lib.rs 是其包根。Cargo 将包根文件传递给 rustc
以构建库或二进制文件。
这里,我们有一个只包含 src/main.rs 的包,这意味着它只包含一个名为 my-project
的二进制包。如果一个包包含 src/main.rs 和 src/lib.rs,它将有两个包:一个二进制包和一个库包,它们的名称与包的名称相同。一个包可以通过在 src/bin 目录中放置文件来拥有多个二进制包:每个文件将是一个单独的二进制包。