Merge pull request #317 from JesseAtSZ/patch-2

Update crate.md
pull/326/head
Sunface 3 years ago committed by GitHub
commit 50e2a0e0e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,29 +1,29 @@
# 包和Package # 包和Package
当读者按照章节顺序读到本章时,意味着你已经几乎具备了参与真实项目开发的能力。但是真实项目远比我们之前的`cargo new`的默认目录结构要复杂好在Rust为我们提供了强大的包管理工具 当读者按照章节顺序读到本章时,意味着你已经几乎具备了参与真实项目开发的能力。但是真实项目远比我们之前的 `cargo new` 的默认目录结构要复杂好在Rust 为我们提供了强大的包管理工具:
- **Package**: 可以用来构建、测试和分享包 - **Package**可以用来构建、测试和分享包
- **工作空间workspace**: 对于大型项目,可以进一步将多个包联合在一起,组织成工作空间 - **工作空间workspace**对于大型项目,可以进一步将多个包联合在一起,组织成工作空间
- **包Crate**: 一个由多个模块组成的树形结构,可以作为三方库进行分发,也可以生成可执行文件进行运行 - **包Crate**一个由多个模块组成的树形结构,可以作为三方库进行分发,也可以生成可执行文件进行运行
- **模块Module**:可以一个文件多个模块,也可以一个文件一个模块,模块可以被认为是真实项目中的代码组织单元 - **模块Module**:可以一个文件多个模块,也可以一个文件一个模块,模块可以被认为是真实项目中的代码组织单元
## 定义 ## 定义
其实`Package`和包很容易被搞混,甚至在很多书中,这两者都是不分的,但是由于官方对此做了明确的区分,因此我们会在本章节中试图(挣扎着)理清这个概念. 其实 `Package` 和包 `crate` 很容易被搞混,甚至在很多书中,这两者都是不分的,但是由于官方对此做了明确的区分,因此我们会在本章节中试图(挣扎着)理清这个概念
#### 包crate #### 包 crate
对于Rust而言包是一个独立的可编译单元它编译后会生成一个可执行文件或者一个库。 对于Rust 而言,包是一个独立的可编译单元,它编译后会生成一个可执行文件或者一个库。
一个包会将相关联的功能打包在一起,使得该功能可以很方便的在多个项目中分享。例如标准库中没有提供但是在三方库中提供的`rand`包,它提供了随机数生成的功能,我们只需要将该包通过`use rand;`引入到当前项目的作用域中,就可以在项目中使用`rand`的功能: `rand::XXX` 一个包会将相关联的功能打包在一起,使得该功能可以很方便的在多个项目中分享。例如标准库中没有提供但是在三方库中提供的 `rand` 包,它提供了随机数生成的功能,我们只需要将该包通过 `use rand;` 引入到当前项目的作用域中,就可以在项目中使用 `rand` 的功能:`rand::XXX`
同一个包中不能有同名的类型,但是在不同包中就可以。例如,虽然`rand`包中,有一个`Rng`特征,可是我们依然可以在自己的项目中定义一个`Rng`,前者通过`rand::Rng`访问,后者通过`Rng`访问,对于编译器而言,这两者的边界非常清晰,不会存在引用歧义。 同一个包中不能有同名的类型,但是在不同包中就可以。例如,虽然 `rand` 包中,有一个 `Rng` 特征,可是我们依然可以在自己的项目中定义一个 `Rng`,前者通过 `rand::Rng` 访问,后者通过 `Rng` 访问,对于编译器而言,这两者的边界非常清晰,不会存在引用歧义。
## Package ## Package
鉴于Rust团队标新立异的起名传统以及包的名称被`crate`占用,库的名称被`library`占用,因此导致我不知道该如何准确的翻译`Package`,遂决定,不翻译,但是大家可以把它理解为一个项目工程,或者一个微服务工程。 鉴于 Rust 团队标新立异的起名传统,以及包的名称被 `crate` 占用,库的名称被 `library` 占用,因此导致我不知道该如何准确的翻译 `Package`,遂决定,不翻译,但是大家可以把它理解为一个项目工程,或者一个微服务工程。
由于`Package`就是一个项目,因此它包含有独立的`Cargo.toml`文件, 以及因为功能性被组织在一起的一个或多个包。一个`package`只能包含**一个**库(library)类型的包, 但是可以包含**多个**二进制可执行类型的包。 由于 `Package` 就是一个项目,因此它包含有独立的 `Cargo.toml` 文件,以及因为功能性被组织在一起的一个或多个包。一个 `Package` 只能包含**一个**库(library)类型的包,但是可以包含**多个**二进制可执行类型的包。
#### 二进制package #### 二进制 Package
让我们来创建一个二进制`package`: 让我们来创建一个二进制 `Package`
```console ```console
$ cargo new my-project $ cargo new my-project
Created binary (application) `my-project` package Created binary (application) `my-project` package
@ -34,12 +34,12 @@ $ ls my-project/src
main.rs main.rs
``` ```
这里Cargo为我们创建了一个名称是`my-project`的`package`, 同时在其中创建了`Cargo.toml`文件,可以看一下该文件,里面并没有提到`src/main.rs`作为程序的入口, 原因是Cargo有一个惯例:**src/main.rs是二进制包的根文件该二进制包的包名跟所属package相同在这里都是my-project**, 所有的代码执行都从该文件中的`fn main()`函数开始。 这里Cargo 为我们创建了一个名称是 `my-project``Package`,同时在其中创建了 `Cargo.toml` 文件,可以看一下该文件,里面并没有提到 `src/main.rs` 作为程序的入口,原因是 Cargo 有一个惯例:**src/main.rs是二进制包的根文件该二进制包的包名跟所属package相同在这里都是my-project**,所有的代码执行都从该文件中的 `fn main()` 函数开始。
使用`cargo run`可以运行该项目,输出:`Hello, world!`. 使用 `cargo run` 可以运行该项目,输出:`Hello, world!`。
#### 库package #### 库 Package
再来创建一个库类型的`package`: 再来创建一个库类型的 `package`
```console ```console
$ cargo new my-test --lib $ cargo new my-test --lib
Created library `my-lib` package Created library `my-lib` package
@ -50,25 +50,25 @@ $ ls my-lib/src
lib.rs lib.rs
``` ```
首先,如果你试图运行`my-test`,会报错: 首先,如果你试图运行 `my-test`,会报错:
```console ```console
$ cargo run $ cargo run
error: a bin target must be available for `cargo run` error: a bin target must be available for `cargo run`
``` ```
原因是库类型的`package`只能作为三方库被其它项目引用,而不能独立运行,只有之前的二进制`package`才可以运行。 原因是库类型的 `Package` 只能作为三方库被其它项目引用,而不能独立运行,只有之前的二进制 `Package` 才可以运行。
`src/main.rs`一样Cargo知道如果一个`package`包含有`src/lib.rs`,意味它包含有一个库类型的同名包`my-lib`,该包的根文件是`src/lib.rs` `src/main.rs` 一样Cargo 知道,如果一个 `Package` 包含有 `src/lib.rs`,意味它包含有一个库类型的同名包 `my-lib`,该包的根文件是 `src/lib.rs`
#### 易混淆的package和包 #### 易混淆的 Package 和包
看完上面,相信大家看出来为何`package`和包容易被混淆了吧?因为你用`cargo new`创建的`package`和它其中包含的包是同名的! 看完上面,相信大家看出来为何 `Package` 和包容易被混淆了吧?因为你用 `cargo new` 创建的 `Package` 和它其中包含的包是同名的!
不过,只要你牢记`package`是一个项目工程,而包只是一个编译单元,基本上也就不会混淆这个两个概念了: `src/main.rs`和`src/lib.rs`都是编译单元,因此它们都是包。 不过,只要你牢记 `Ppackage` 是一个项目工程,而包只是一个编译单元,基本上也就不会混淆这个两个概念了`src/main.rs` 和 `src/lib.rs` 都是编译单元,因此它们都是包。
#### 典型的`package`结构 #### 典型的 `Package` 结构
上面创建的`package`中仅包含`src/main.rs`文件,意味着它仅包含一个二进制同名包`my-project`。如果一个`package`同时拥有`src/main.rs`和`src/lib.rs`,那就意味着它包含两个包:库包和二进制包,这两个包名也都是`my-project` —— 都与`package`同名。 上面创建的 `Package` 中仅包含 `src/main.rs` 文件,意味着它仅包含一个二进制同名包 `my-project`。如果一个 `Package` 同时拥有 `src/main.rs``src/lib.rs`,那就意味着它包含两个包:库包和二进制包,这两个包名也都是 `my-project` —— 都与 `package` 同名。
一个真实项目中典型的`package`,会包含多个二进制包,这些包文件被放在`src/bin`目录下,每一个文件都是独立的二进制包,同时也会包含一个库包,该包只能存在一个`src/lib.rs` 一个真实项目中典型的 `Package`,会包含多个二进制包,这些包文件被放在 `src/bin` 目录下,每一个文件都是独立的二进制包,同时也会包含一个库包,该包只能存在一个 `src/lib.rs`
```css ```css
. .
├── Cargo.toml ├── Cargo.toml
@ -87,14 +87,14 @@ error: a bin target must be available for `cargo run`
└── simple_example.rs └── simple_example.rs
``` ```
- 唯一库包, `src/lib.rs` - 唯一库包`src/lib.rs`
- 默认二进制包 `src/main.rs`,编译后生成的可执行文件与`package`同名 - 默认二进制包`src/main.rs`,编译后生成的可执行文件与`package`同名
- 其余二进制包`src/bin/main1.rs`和`src/bin/main2.rs`,它们会分别生成一个文件同名的二进制可执行文件 - 其余二进制包`src/bin/main1.rs` 和 `src/bin/main2.rs`,它们会分别生成一个文件同名的二进制可执行文件
- 集成测试文件:`tests`目录下 - 集成测试文件:`tests` 目录下
- 性能测试benchmark文件: `benches`目录下 - 性能测试benchmark文件`benches` 目录下
- 项目示例: `examples`目录下 - 项目示例`examples` 目录下
这种目录结构基本上是Rust的标准目录结构在`github`的大多数项目上,你都将看到它的身影。 这种目录结构基本上是 Rust 的标准目录结构,在 `github` 的大多数项目上,你都将看到它的身影。
理解了包的概念,我们再来看看构成包的基本单元:模块。 理解了包的概念,我们再来看看构成包的基本单元:模块。

Loading…
Cancel
Save