包和 Crate
我们首先要介绍模块系统中的包和 crate。
Crate 是 Rust 编译器一次处理的最小代码单位。即使你运行 rustc 而不是 cargo,并传入单个源代码文件(就像我们在第 1 章“Rust 程序基础”中做的那样),编译器也会将该文件视为一个 crate。Crate 可以包含模块,而模块也可以定义在与该 crate 一起编译的其他文件中,接下来的章节会介绍这一点。
Crate 有两种形式:二进制 crate 和库 crate。二进制 crate 是可以编译为可运行可执行文件的程序,例如命令行程序或服务器。每个二进制 crate 都必须有一个名为 main 的函数,用来定义可执行文件运行时的行为。目前为止,我们创建的所有 crate 都是二进制 crate。
库 crate 没有 main 函数,也不会编译为可执行文件。相反,它们定义了供多个项目共享的功能。例如,我们在第 2 章使用的 rand crate 提供了生成随机数的功能。Rustacean 大多数时候说“crate”时,指的都是库 crate;他们也会将“crate”和编程中的通用概念“库”互换使用。
Crate 根是 Rust 编译器开始处理的源文件,也是 crate 根模块的组成部分(我们会在“使用模块控制作用域和隐私性”一节中详细介绍模块)。
包(package)是一个或多个 crate 的集合,提供一组功能。包中包含一个 Cargo.toml 文件,用于描述如何构建这些 crate。Cargo 本身也是一个包,其中包含你一直用来构建代码的命令行工具对应的二进制 crate。Cargo 包还包含一个供该二进制 crate 依赖的库 crate。其他项目可以依赖 Cargo 的库 crate,以使用 Cargo 命令行工具所采用的相同逻辑。
一个包可以包含任意数量的二进制 crate,但最多只能包含一个库 crate。一个包至少必须包含一个 crate,可以是库 crate,也可以是二进制 crate。
下面来看看创建包时会发生什么。首先,输入命令 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
your text editor and note that there’s no mention of src/main.rs. Cargo
directory contains src/lib.rs, the package contains a library crate with the
and src/lib.rs, it has two crates: a binary and a library, both with the same
运行 cargo new my-project 后,我们使用 ls 查看 Cargo 创建了什么。在 my-project 目录中,有一个 Cargo.toml 文件,这就构成了一个包。还有一个 src 目录,其中包含 main.rs。在文本编辑器中打开 Cargo.toml,注意其中没有提到 src/main.rs。Cargo 遵循一项约定:src/main.rs 是与包同名的二进制 crate 的 crate 根。同样,如果包目录中包含 src/lib.rs,Cargo 就会知道该包包含一个与包同名的库 crate,而 src/lib.rs 是它的 crate 根。Cargo 会将 crate 根文件传递给 rustc,以构建库或二进制程序。
这里的包只包含 src/main.rs,因此它只包含一个名为 my-project 的二进制 crate。如果包同时包含 src/main.rs 和 src/lib.rs,就会有两个 crate:一个二进制 crate 和一个库 crate,它们都与包同名。将文件放入 src/bin 目录中,还可以让一个包拥有多个二进制 crate:每个文件都会成为一个独立的二进制 crate。