# 包和Package
当读者按照章节顺序读到本章时，意味着你已经几乎具备了参与真实项目开发的能力。但是真实项目远比我们之前的`cargo new`的默认目录结构要复杂，好在，Rust为我们提供了强大的包管理工具：

- **Package**: 可以用来构建、测试和分享包
- **工作空间workspace**: 对于大型项目，可以进一步将多个包联合在一起，组织成工作空间
- **包Crate**: 一个由多个模块组成的树形结构，可以作为三方库进行分发，也可以生成可执行文件进行运行
- **模块Module**：可以一个文件多个模块，也可以一个文件一个模块，模块可以被认为是真实项目中的代码组织单元

## 定义
其实`Package`和包很容易被搞混，甚至在很多书中，这两者都是不分的，但是由于官方对此做了明确的区分，因此我们会在本章节中试图(挣扎着)理清这个概念.

#### 包crate
对于Rust而言，包是一个独立的可编译单元，它编译后会生成一个可执行文件或者一个库。

一个包会将相关联的功能打包在一起，使得该功能可以很方便的在多个项目中分享。例如标准库中没有提供但是在三方库中提供的`rand`包，它提供了随机数生成的功能，我们只需要将该包通过`use rand;`引入到当前项目的作用域中，就可以在项目中使用`rand`的功能: `rand::XXX`。

同一个包中不能有同名的类型，但是在不同包中就可以。例如，虽然`rand`包中，有一个`Rng`特征，可是我们依然可以在自己的项目中定义一个`Rng`，前者通过`rand::Rng`访问，后者通过`Rng`访问，对于编译器而言，这两者的边界非常清晰，不会存在引用歧义。


## Package
鉴于Rust团队标新立异的起名传统，以及包的名称被`crate`占用，库的名称被`library`占用，因此导致我不知道该如何准确的翻译`Package`，遂决定，不翻译，但是大家可以把它理解为一个项目工程，或者一个微服务工程。

由于`Package`就是一个项目，因此它包含有独立的`Cargo.toml`文件, 以及因为功能性被组织在一起的一个或多个包。一个`package`只能包含**一个**库(library)类型的包, 但是可以包含**多个**二进制可执行类型的包。

#### 二进制package
让我们来创建一个二进制`package`:
```console
$ cargo new my-project
     Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs
```

这里，Cargo为我们创建了一个名称是`my-project`的`package`, 同时在其中创建了`Cargo.toml`文件，可以看一下该文件，里面并没有提到`src/main.rs`作为程序的入口, 原因是Cargo有一个惯例：**src/main.rs是二进制包的根文件，该二进制包的包名跟所属package相同，在这里都是my-project**, 所有的代码执行都从该文件中的`fn main()`函数开始。

使用`cargo run`可以运行该项目，输出:`Hello, world!`.

#### 库package
再来创建一个库类型的`package`:
```console
$ cargo new my-test --lib
     Created library `my-lib` package
$ ls my-lib
Cargo.toml
src
$ ls my-lib/src
lib.rs
```

首先，如果你试图运行`my-test`，会报错：
```console
$ cargo run
error: a bin target must be available for `cargo run`
```
原因是库类型的`package`只能作为三方库被其它项目引用，而不能独立运行，只有之前的二进制`package`才可以运行。

与`src/main.js`一样，Cargo知道，如果一个`package`包含有`src/lib.js`，意味它包含有一个库类型的同名包`my-lib`，该包的根文件是`src/lib.js`

#### 易混淆的package和包
看完上面，相信大家看出来为何`package`和包容易被混淆了吧？因为你用`cargo new`创建的`package`和它其中包含的包是同名的！

不过，只要你牢记`package`是一个项目工程，而包只是一个编译单元，基本上也就不会混淆这个两个概念了: `src/main.rs`和`src/lib.rs`都是编译单元，因此它们都是包。


#### 典型的`package`结构
上面创建的`package`中仅包含`src/main.rs`文件，意味着它仅包含一个二进制同名包`my-project`。如果一个`package`同时拥有`src/main.js`和`src/lib.rs`，那就意味着它包含两个包：库包和二进制包，这两个包名也都是`my-project` —— 都与`package`同名。

一个真实项目中典型的`package`，会包含多个二进制包，这些包文件被放在`src/bin`目录下，每一个文件都是独立的二进制包，同时也会包含一个库包，该包只能存在一个`src/lib.rs`：
```css
.
├── Cargo.toml
├── Cargo.lock
├── src
│   ├── main.rs
│   ├── lib.rs
│   └── bin
│       └── main1.rs
│       └── main2.rs
├── tests
│   └── some_integration_tests.rs
├── benches
│   └── simple_bench.rs
└── examples
    └── simple_example.rs
```

- 唯一库包, `src/lib.rs`
- 默认二进制包， `src/main.rs`，编译后生成的可执行文件与`package`同名
- 其余二进制包，`src/bin/main1.rs`和`src/bin/main2.rs`，它们会分别生成一个文件同名的二进制可执行文件
- 集成测试文件：`tests`目录下
- 性能测试benchmark文件: `benches`目录下
- 项目示例: `examples`目录下


这种目录结构基本上是Rust的标准目录结构，在`github`的大多数项目上，你都将看到它的身影。

理解了包的概念，我们再来看看构成包的基本单元：模块。