Rust 入门 包 (二十一)
能读到本章节,意味着你已经 几乎具备了参与真实项目开发的能力。但是真实项目远比我们之前的cargo new 的默认目录结构要复杂,好在,Rust为我们提供了强大的包管理工具
1.项目 (Package),可以用来构建,测试和分享包
2.工作空间(WorkSpace),对于大型项目,可以进一步将多个包联合在一起,组织成工作空间
3.包(Crate) 一个由多个模块组成的树形结构,可以作为三方库进行分发,也可以生成可执行文件进行运行
4.模块(Module) : 可以一个文件多个模块,也可以一个文件一个模块,模块可以被认为是真实项目中的代码组织单元
定义
其实项目 Package 和包 Crate 很容易被搞混,甚至在很多书中, 这两者都是不分的,但是由于官方对此做了明确的区分,因此我们会在本章节中试图(挣扎着) 理清这个概念。
包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
$ 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 :
$ cargo new my-lib --lib
Created library `my-lib` package
$ ls my-lib
Cargo.toml
src
$ ls my-lib/src
lib.rs
首先,如果你试图运行my-lib ,会报错:
$ cargo run
error: a bin target must be available for `cargo run`
原因是库类型的Package 只能w作为三方库被其它项目引用,而不能独立运行,只有之前的二进制Package才可以运行。
与 src/mian.rs 一样,Cargo 知道,如果一个Package 包含有 src/lib.rs, 意味它包含有一个库类型的同名包 my-lib 该包的根文件是 src/lib.rs.
易混淆的Package 和 包
看完上面,相信大家看出来为何Package 和 包 容易被混淆来把?因为你用 cargo new 创建的Package 和它其中包含的包是同名的
不过,只要你牢记Package 是一个项目工程, 而 包只是一个编译单元,也就不会在混淆这两个概念 : src/main.rs 和 src/lib.rs 都是编译单元,因此他们都是包。
典型的Package结构
上面创建的Package 中仅包含 src/main.rs 文件,意味着它仅包含一个二进制同名包 my-project。 如果是一个Package 同时拥有src/main.rs 和 src/lib.rs, 那就意味着它包含两个包: 库包和二进制包, 这两个包名也是my-project -- 都与Package 同名。
一个真实项目中典型的Package ,会包包含多个二进制包,这些包文件被放在src/bin 目录下,每一个文件都是独立的二进制包,同时也会包含一个库包,该包只能够存在一个src/lib.rs:
.
├── 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
1 唯一库包: src/lib.rs
2. 默认二进制包: src/main.rs, 编译后生成的可执行文件与Package同名
3.其余二进制包: src/bin/main1.rs 和 src/bin/main2.rs, 它们会分别生成一个而你将同名的二进制可执行文件。
4.集成测试文件: tests 目录下
5.基准性能测试 benchmark 文件,:benches 目录下
6. 项目示例: examples目录下
这中目录结构基本上是Rust的标准目录结构,在Github 的大多数项目上,你都将看到它的身影。理解来包的概念,我们再来看看构成包的基本单元: 模块。