Updated src/packages_crates_and_modules/packages_and_crates.md'.

This commit is contained in:
Hector PENG
2026-03-14 17:44:19 +08:00
parent 27967ab48d
commit 700b5a62b0
4 changed files with 19 additions and 28 deletions

View File

@@ -1,8 +1,6 @@
[package]
name = "my-project"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
edition = "2024"
[dependencies]

View File

@@ -4,19 +4,17 @@
到目前为止我们已编写的程序都在一个文件的一个模组中。随着项目增长咱们应通过把代码拆分为多个模组然后拆分为多个文件来组织代码。一个包可以包含多个二进制代码箱也可以包含一个库代码箱。随着包的增长咱们可提取各个部分到单独的代码箱而成为外部依赖项。这一章介绍所有这些技巧。对于由一组共同发展互相关联的包组成的超大型项目Cargo 提供了 *工作空间workspaces*,我们将在第 14 章中的 [Cargo 工作空间](../crates-io/workspace.md) 小节中介绍。
我们还将讨论封装实现细节,这让咱们可在更高级别重用代码:一旦咱们实现了某项操作,其他代码可以通过其公共接口调用咱们的代码,而不必了解实现的工作原理。咱们编写代码的方式定义了哪些部分属于公开供其他代码使用的,以及哪些部分属于咱们保留更改权利的私有实现细节。这是限制咱们必须记住细节数量的另一方式。
我们还将讨论实现细节进行封装,这让咱们可在更高级别重用代码:一旦咱们实现了某项操作,其他代码可以通过其公共接口调用咱们的代码,而不必了解实现的工作原理。咱们编写代码的方式定义了哪些部分属于公开供其他代码使用的,以及哪些部分属于咱们保留更改权利的私有实现细节。这是咱们必须记住细节数量有所限制的另一方式。
一个相关的概念是作用域:代码写下之处的嵌套上下文,都有一组被定义为 “在作用域中” 的名字。在阅读、编写及编译代码时,程序员和编译器都需要知道,某个特定点位上的特定名字,是否引用了某个变量、函数、结构体、枚举、模组、常量,或其他项目及该项目的含义。咱们可以创建作用域,并改变哪些名字在作用域内或在作用域外。在同一个作用域中,咱们不能有两个同名的项目;有一些可用于解决名字冲突的工具。
Rust 有着数项特性,可以让咱们管理咱们代码的组织,包括哪些细节会暴露,哪些细节属于私有的,以及咱们程序中的各个作用域中都有哪些名字。这些特性有时统称为 *模组系统module system*,包括:
一个相关的概念是作用域:代码写下之处的嵌套上下文,都有一组被定义为 “在作用域中” 的名字。在阅读、编写及编译代码时,程序员和编译器都需要知道,某个特定点位上的某一特定名字,是否引用了某个变量、函数、结构体、枚举、模组、常量,或其他项目及该项目的含义。咱们可以创建作用域,并改变哪些名字在作用域内或在作用域外。在同一个作用域中,咱们不能有两个同名的项目;有一些可用于解决名字冲突的工具。
Rust 有着数项可以让咱们管理咱们代码的组织的特性,包括哪些细节会暴露,哪些细节属于私有的,以及咱们程序中的各个作用域中都有哪些名字。这些特性有时统称为 *模组系统module system*,包括:
- **包package**:让咱们构建、测试和共享代码箱的 Cargo 特性;
- **代码箱crate**:产生库或可执行程序的模组树;
- **模组module** 与 **`use` 关键字**:让咱们可以控制路径的组织、作用域及隐私;
- **路径path**:命名项目的一种方式,例如结构体、函数或模组。
在这一章中,我们将介绍所有这些特性,讨论他们如何交互,并解释如何使用他们来管理作用域。到本章结束时,咱们应对模组系统有扎实了解,并能像专业人士一样,使用作用域!

View File

@@ -7,9 +7,6 @@
## 创建项目的目录
**Creating a Project Directory**
首先,咱们将创建一个存储咱们 Rust 代码的目录。对于 Rust 来说,代码存放在哪里并不重要,但对于本书中的练习和项目,我们建议在咱们的主目录下,创建一个 `projects` 目录,并将咱们的所有项目,都放在那里。
请打开某个终端,并输入以下命令,创建 `projects` 目录,并在 `projects` 目录下,创建出这个 "Hello, world!" 的项目目录。
@@ -32,7 +29,7 @@ $ cd hello_world
> cd hello_world
```
## 编写并运行一个 Rust 程序
## Rust 程序基础
接下来,请创建一个新的源文件,并将其命名为 `main.rs`。Rust 文件总是以 `.rs` 扩展名结尾。如果咱们在文件名中,使用了多个单词,惯例是要使用下划线,分隔这些单词。例如,请使用 `hello_world.rs`,而不是 `helloworld.rs`

View File

@@ -1,28 +1,26 @@
# 包与代码箱
# 代码包与代码箱
**Packages and Crates**
我们将介绍的模组系统的前两个部分,分别是代码包与代码箱。
所谓 *代码箱crate*,是 Rust 编译器一次考虑的最小代码量。即使咱们运行 `rustc` 而不是 `cargo`,并传递单个源代码文件(正如我们在第 1 章中 [Rust 程序基础](../getting_started/hello_world.md#rust-程序基础) 小节中所做的那样),编译器也会将该文件视为一个代码箱。代码箱可以包含模组,而模组可以定义在与该代码箱一起编译的其他文件中,正如我们将在接下来的小节中看到的那样。
我们要介绍的模组系统头两个部分,分别是代码包与代码箱。
代码箱可以有两种形式:二进制代码箱或库代码箱。所谓 *二进制代码箱binary crates*,属于可以咱们编译为咱们可运行的可执行文件的程序,例如命令行程序或服务器。每个二进制代码箱都必须有个名为 `main` 的函数,定义可执行文件运行时会发生什么。到目前为止我们创建的所有代码箱都属于二进制代码箱。
*代码箱crate* 是 Rust 编译器一次要考虑的最小代码量。即使咱们运行的是 `rustc` 而不是 `cargo`,并只传递了一个源代码文件(就像我们在第 1 章 “编写和运行 Rust 程序” 小节中所做的那样),编译器也会将该文件,视为一个代码箱。代码箱可以包含模组,模组也可以定义在与该代码箱一起编译的其他文件中,正如我们将在接下来的小节中看到的那样
所谓 *代码箱,library crates*,没有 `main` 函数,并且他们不会编译为可执行文件。相反,他们定义了意图在多个项目中共享的功能。例如,我们在 [第 2 章](../Ch02_Programming_a_Guessing_Game.md#生成随机数) 中用到 `rand` 代码箱就提供了生成随机数的功能。大多数时候Rustaceans 说 “代码箱crate” 时,他们指的是库代码箱,并且他们会将 “代码箱” 与一般编程概念的 “库library” 互换使用
代码箱有两种形式:二进制代码箱或库代码箱。*二进制代码箱binary crates* 属于可以编译成咱们可以运行的可执行文件的程序,例如命令行程序或服务器。每个二进制代码箱,都必须有个名为 `main` 的函数,定义出可执行文件运行时会发生什么。到目前为止,我们创建的所有代码箱,都是二进制代码箱
所谓 *代码箱根crate root*,是 Rust 编译器开始之处的源代码文件,并构成了咱们代码箱的 *根模组root module*(我们将在 [在模组下控制作用域及隐私](/packages_crates_and_modules/defining_modules.md) 处深入解释模组)
*库代码箱library crates* 没有 `main` 函数,也不会编译成可执行文件。相反,他们定义了旨在与多个项目共享的功能。例如,我们在 [第 2 章](../Ch02_Programming_a_Guessing_Game.md#生成随机数) 中,使用的 `rand` 代码箱,就提供了生成随机数的功能。大多数时候,当 Rustaceans 说 “代码箱crate” 时,他们指的是库代码箱,而且他们会将 “代码箱”,与一般的编程概念 “库library” 互换使用
所谓 *package*,是提供一组功能的一或多个代码箱的捆绑。包会包含一个 `Cargo.toml` 文件描述如何构建这些代码箱。Cargo 实际上是个包包含着咱们用来构建代码的命令行工具的二进制包。Cargo 包还包含了二进制代码箱所依赖的库代码箱。其他项目可依赖 Cargo 库代码箱,使用 Cargo 命令行工具使用的同样逻辑
*代码箱根crate root*,则是个 Rust 编译器开始之处的源代码文件,并构成了咱们代码箱的 *根模组root module*(我们将在 [定义控制作用域和隐私的模组](/packages_crates_and_modules/defining_modules.md) 小节,深入探讨模组)
一个包可以包含任意数量的二进制代码箱,但最多只有一个库代码箱。一个包必须至少包含一个代码箱,无论是库还是二进制代码箱
*package* 是提供了一组功能的一或多个代码箱的捆绑。包会包含一个描述如何构建这些代码箱的 `Cargo.toml` 文件。Cargo 实际上就是个包含了咱们用来构建代码的命令行工具的包。Cargo 包还包含该二进制代码箱所依赖的库代码箱。其他项目可以依赖于 Cargo 的库代码箱,使用与 Cargo 这个命令行工具,所使用的同样逻辑。
一个包可以包含任意数量的二进制代码箱,但最多只能包含一个库代码箱。一个包必须至少包含一个代码箱,无论是库代码箱,还是二进制代码箱。
我们来看看,在我们创建某个软件包时,会发生什么。首先,我们输入命令 `cargo new`
我们来看看当我们创建包时会发生什么。首先,我们输入命令 `cargo new my-project`
```console
$ cargo new my-project --vcs=none
Created binary (application) `my-project` package
$ cargo new my-project
Creating binary (application) `my-project` package
note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
$ ls my-project
Cargo.toml src
$ ls my-project/src
@@ -30,9 +28,9 @@ main.rs
```
运行 `cargo new` 后,我们使用 `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` 以构建出该库或二进制程序。
在我们运行 `cargo new` 后,我们使用 `ls` 查看 Cargo 创建了什么。在 `my-project` 目录,有个 `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` 目录中放置一些文件,包可以有多个二进制代码箱:每个文件都将是个单独的二进制代码箱。
这里,我们有个仅包含 `src/main.rs` 的包,意味着他包含一个名为 `my-project` 的二进制代码箱。某个包包含 `src/main.rs` `src/lib.rs`,那么他就有两个代码箱:一个二进制代码箱和一个库代码箱,二者均有着与包相同的名字。通过放置文件与 `src/bin` 目录下,一个包可以有多个二进制代码箱:每个文件都将是个单独的二进制代码箱。
End