Rust系统编程之项目管理

1.Crate

一个由多个模块组成的树形结构,可以作为三方库进行分发,也可以生成可执行文件进行运行。将多个功能打包到一起形成一个代码集合箱,一个crate是一个编译单元。

1.1 binary crate

一个二进制crate,它的充分必要条件是会有./src/main.rs这个文件,是整个用于执行crate的入口文件。

cargo新建binary crate命令:

1
cargo new test_lib --lib

1.2 library crate

一个library crate,它的充分必要条件是有./src/lib.rs 这个文件。

2.Package

Package就是一个工程,包含了1个或者n个crate以及测试、文档等,一个Package包含一个Cargo.toml配置文件。

规则:

  • 一个package最多包含一个library crate
  • 一个package可以包含任意多的binary crate
  • 一个package至少要包含一个crate(无论是binary或是library)

典型的package解构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.
├── 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

3.Module

Module让我们可以将一个 crate 中的代码进行分组,以提高可读性与重用性。

Module相当于在一个crate中的更小的功能单元,一个crate可能使用了n个module,使用mod xxx的方式来引用一个module

3.1 代码搜索规则

在rust编译crate时会从以下路径中寻找module的代码:

  • 内联,在大括号中,当mod garden后方不是一个分号而是一个大括号
  • 在文件 src/garden.rs
  • 在文件 src/garden/mod.rs

并且可以在module中引用其他的module,搜索方式如上。

一旦一个模块是crate的一部分,你可以在隐私规则允许的前提下,从同一个crate内的任意地方,通过代码路径引用该模块的代码。

举例而言,一个garden vegetables模块下的Asparagus类型可以在crate::garden::vegetables::Asparagus被找到。

3.2 隐私规则

一个模块里的代码默认对其父模块私有,但是子模块可以访问到父模块。为了使一个模块公用,应当在声明时使用pub mod替代mod。为了使一个公用模块内部的成员公用,应当在成员声明前使用pub

3.3 模块树

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
fn seat_at_table() {}
}
mod serving {
fn take_order() {}
fn serve_order() {}
fn take_payment() {}
}
}

此时从crate为根节点会生成如下的模块树结构:

1
2
3
4
5
6
7
8
9
crate
└── front_of_house
├── hosting
│ ├── add_to_waitlist
│ └── seat_at_table
└── serving
├── take_order
├── serve_order
└── take_payment

add_to_waitlistseat_at_table互为兄弟模块,front_of_househosting构成父子模块。

3.4 引用路径搜索规则

在模块树中找到一个module的位置,我们使用指定路径的方式,就像在文件系统种使用路径一样。为了调用一个函数,我们需要知道它的代码路径。

路径分两种:

  • 绝对路径absolute path)是以 crate 根(root)开头的全路径;对于外部 crate 的代码,是以 crate 名开头的绝对路径,对于对于当前 crate 的代码,则以字面值 crate 开头。
  • 相对路径relative path)从当前模块开始,以 selfsuper 或当前模块的标识符开头,super关键字用于访问父模块中的项。

绝对路径和相对路径都后跟一个或多个由双冒号(::)分割路径中的module

3.5 use关键字

use关键字简化了路径搜索,可以在一个module种使用use来声明一个作用时间更久的软链接的方式将其他module的代码引入当前作用域。

1
2
3
4
5
6
7
8
9
10
11
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}

use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}

嵌套引用:

1
2
3
4
5
6
use std::cmp::Ordering;
use std::io;

==>

use std::{cmp::Ordering, io};

引用所有公有项:

1
use std::collections::*;

3.6 as关键字

为类型起别名

1
2
3
4
5
6
7
8
9
10
use std::fmt::Result;
use std::io::Result as IoResult;

fn function1() -> Result {
// --snip--
}

fn function2() -> IoResult<()> {
// --snip--
}

3.7 pub use重导出

在一个作用域内使用use将其他module的项导入进来后,这个项在这个作用域外面还是私有的。如果想外面的代码访问这个项跟访问引入那个项的作用域的权限一致的话,可以使用pub use关键字将那个项进行重导出。

1
2
3
4
5
6
7
8
9
10
11
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}

在这个修改之前,外部代码需要使用路径 restaurant::front_of_house::hosting::add_to_waitlist() 来调用 add_to_waitlist 函数。现在这个 pub use 从根模块重导出了 hosting 模块,外部代码现在可以使用路径 restaurant::hosting::add_to_waitlist来调用。


Rust系统编程之项目管理
http://helloymf.github.io/2023/04/14/rust-xi-tong-bian-cheng-zhi-xiang-mu-guan-li/
作者
JNZ
许可协议