模块化的四个层级

  1. Functions
  2. Modules:有四种形式
    1. 在文件内,使用**mod**定义的内联模块(inline module
    2. 2018版本中,一个文件本身就是一个模块,一个和文件同名的文件夹是它的子模块
    3. 2015版本中,一个文件夹是一个模块,根模块是**mod.rs**,其余文件是它的子模块
  3. Crates:有两种形式
    1. 可执行executable crate中,位于自身src下的**lib.rs**文件
    2. Cargo.toml中指定的外部(Dependencycrate
      1. 通过文件路径(Path)指定
      2. 通过git地址指定
      3. 通过Crates.io中的crate名指定
  4. Workspaces
    1. 在同一个文件夹下管理多个crates

结构体和枚举

结构体所有字段默认私有,即使结构体前有pub关键字,也需要在字段前单独加**pub**关键字,另外需要为这样的结构体配一个关联函数来初始化实例

枚举前加上pub关键字时,枚举的所有字段也成为公有的,可以直接使用

Modules

模块路径

绝对路径:从模块根开始,即从crate开始往下写
相对路径:使用self从当前模块开始,使用super从父模块开始

内联模块

  • 默认情况下,模块中的内容都是私有的
  • 使用pub关键字使其外部可访问

示例:

  1. fn main() {
  2. greetings::hello();
  3. }
  4. mod greetings {
  5. // ⭐️ 默认情况下,模块中的内容都是私有的
  6. pub fn hello() { // ⭐️ 使用pub关键字使其外部可访问
  7. println!("Hello, world!");
  8. }
  9. }

私有函数能够被当前模块子模块调用:

  • self引用模块自己
  • super引用父模块

示例:

  1. // 1.调用模块自身的私有方法
  2. fn main() {
  3. phrases::greet();
  4. }
  5. mod phrases {
  6. pub fn greet() {
  7. hello(); // 或者使用 `self::hello();`
  8. }
  9. fn hello() {
  10. println!("Hello, world!");
  11. }
  12. }
  13. // 2.调用父模块的私有方法
  14. fn main() {
  15. phrases::greetings::hello();
  16. }
  17. mod phrases {
  18. fn private_fn() {
  19. println!("Hello, world!");
  20. }
  21. // 定义子模块
  22. pub mod greetings {
  23. pub fn hello() {
  24. // 调用父模块私有方法
  25. super::private_fn();
  26. }
  27. }
  28. }

文件即模块

  • 引用相同文件夹下的文件模块

示例:

  1. // ↳ main.rs
  2. mod greetings; // 导入greetings模块
  3. fn main() {
  4. greetings::hello();
  5. }
  6. // ↳ greetings.rs
  7. // ⭐️ 不用使用mod定义,因为文件本身就是一个模块
  8. pub fn hello() {
  9. println!("Hello, world!");
  10. }

文件模块与子模块

2015和2018的对比:

图片.png
2015版本中,要么用foo.rs,要么用foo/mod.rs定义模块,如果foo子模块,那么必须用第二种方式
2018版本中,foo.rs的子模块被放在foo/

参考:
No more mod.rs

2015版本用法

mod.rs in the directory module root is the entry point to the directory module. All other files in that directory root, act as sub-modules of the directory module.

  • mod.rs文件夹模块入口点
  • 文件夹下的所有其他文件模块文件夹模块子模块

2018版示例

  • 同级模块/文件可以直接使用
  • 再下级的子模块需要声明pub

模块树:
图片.png

  1. 写在一起的情况 ```rust // 父作用域 // 即 crate 作用域下 fn main() { // 可以直接使用同级的模块 a::hello(); // 同级模块下的子模块需要使用pub声明 a::b::world(); }

mod a { // a作用域下 pub fn hello() { println!(“Hello”) }

  1. // 子模块需要暴露,才能被父作用域下的main使用
  2. pub mod b {
  3. pub fn world() {
  4. println!("world")
  5. }
  6. }

}

  1. 2. 使用模块文件的情况
  2. ```rust
  3. // ↳ main.rs
  4. // crate的作用域下
  5. // 声明使用同级的a模块
  6. mod a;
  7. fn main() {
  8. a::hello();
  9. a::b::world();
  10. }
  11. // a模块
  12. // a的作用域下
  13. // ↳ a.rs
  14. pub mod b; // 二次导出 b 模块
  15. pub fn hello() {
  16. println!("Hello")
  17. }
  18. // b模块
  19. // ↳ a / b.rs
  20. pub fn world() {
  21. println!("world")
  22. }

Crates

Crates are a bit similar to the packages in some other languages. Crates compile individually. (cargo package) If the crate has child file modules, those files will get merged with the crate file and compile as a single unit.

A crate can produce an executable/ a binary or a library. src/main.rs is the crate root/ entry point for a binary crate src/lib.rs is the entry point for a library crate.

Crate分为两种“

  • binary crate,入口点:src/main.rs
  • library crate,入口点:src/lib.rs

src/main是二进制crate的根,src/lib是库crate的根,在模块树中,它们就是根模块,叫做**crate**

binary crate中使用lib.rs

常用的模式:可以在lib.rs中写功能,然后在main.rs中引用lib.rs

示例:
main.rs中使用extern crate <project_name>语句来引入lib.rs
lib.rs中暴露其他文件模块

  1. // # 文件结构
  2. phrases
  3. ├── Cargo.toml
  4. └── src
  5. ├── greetings.rs
  6. ├── lib.rs
  7. └── main.rs
  8. // 02. phrases/src/main.rs
  9. extern crate phrases; // 引用lib.rs
  10. fn main() {
  11. phrases::greetings::hello();
  12. }
  13. // 03. phrases/src/lib.rs
  14. pub mod greetings; // 暴露其他文件模块
  15. // 01. phrases/src/greetings.rs
  16. pub fn hello() {
  17. println!("Hello, world!");
  18. }

引入外部Crates

  1. 通过相对路径引入

[dependencies]
greetings = { path = "greetings" }

  1. 通过git地址引入

[dependencies]
rocket = { git = "https://github.com/SergioBenitez/Rocket" }

  1. 通过Crates.io名称引入

[dependencies]
test_crate_hello_world = "0.1.0"

Workspaces

Workspaces用来在一个项目里管理多个crates

Rust uses a shared build directory under the project root, while running cargo build from the project root.

运行cargo build的时候,Rust把多个crates编译好的依赖放到**shared build directory**中,避免了为每个**crate**生成重复的依赖

project的任何目录下运行cargo命令,等同于在project root下运行命令,避免了切换当前目录

Use关键字

  1. 使用use关键字能简化模块的引入写法,可以使用**as**来指定别名
  2. Re-exporting,二次暴露

Rust中默认所有项(函数、方法、结构体、枚举、模块和常量)都是私有的。

父模块中的项不能使用子模块中的私有项,但是子模块中的项可以使用他们父模块中的项。

使用 *(glob 运算符)可以将此模块下的所有公有项引入作用域

preludes

Even some modules inside std crate (ex.std::io) and many libraries (ex. Diesel) are having their own prelude modules.

一些std库和第三方库有自己的prelude模块

But preludes are used to create a single place to import all important components which are required while using the library. They do not load automatically unless you imported them manually. Only std::prelude imports automatically in every Rust programs.

preludes是用来导入外部库中重要组件的一个地方
这些preludes需要手动加载
只有**std::prelude**会自动加载