开始
rust 的模块化包含以下概念
- 包:一个包包含多个 crates,每个包都有一个
Cargo.toml
文件,一个包可以看做一个项目 - crates:一个 crates 是一个编译单元,可以是一个可执行文件或一个库
- 模块:一个模块表示一个命名空间,一个 crates 中包含多个模块,可以控制模块的可访问性
- 路径:访问一个模块或模块成员的方式,使用
::
作为分隔符
包和 crate
crate 有两种形式
- 二进制项:二进制项可以被编译为一个可执行文件,必须包含一个
main
函数 - 库:库没有
main
函数,其中定义一些类型或函数,可供其他 crate 使用
一个包可以看做一个项目,使用 cargo new
命令创建,其中包含一个 Cargo.toml
文件,用于管理依赖
一个包中至少包含一个 crate,最多包含一个库 crate,可以包含任意多个二进制 crate
每个 crate 都至少有一个根模块 crate
,也称为 crate 根,cargo 有以下默认约定
src/main.rs
:与包同名的二进制 crate 根src/lib.rs
:与包同名的库 crate 根src/bin
:存放其他的二进制 crate
模块
一个模块可以看做一个命名空间
- 使用
mod
关键字声明一个子模块 - 使用
pub
关键字控制模块的可访问性 - 使用
use
关键字引入模块
模块组织形式
一个 crate 中的模块被组织成一个树形结构,支持内联和多文件两种形式
-
内联:使用
mod
关键字声明一个模块后,紧跟一个代码块,在代码块中编写模块的代码1
2
3
4
5
6
7
8
9
10// 通过crate::module访问module模块
// 通过crate::module::submodule访问子模块
mod module {
struct Tuple(i32, i32);
fn foo(x: i32, y: i32) {}
mod submodule {
fn foo(x: i32, y: i32) {}
}
} -
多文件:利用文件树的形式,在父模块中使用
mod
关键字声明一个子模块,cargo 会在子目录中查找子模块1
2
3
4
5src
├──module // 与module.rs同名
│ └──submodule.rs
├──main.rs
└──module.rsmain.rs
中使用mod module;
声明 module 子模块,cargo 会查找module.rs
module.rs
中使用mod submodule;
声明 submodule 子模块,cargo 会查找module/submodule.rs
- 使用
crate::module
访问 module 模块,使用crate::module::submodule
访问 submodule 模块
内联和多文件两种形式可以混合使用
将 submodule.rs
中的模块代码以内联形式移动到 module.rs
中
1 | // 依然使用crate::module::submodule访问submodule |
模块可访问性
在默认情况下,模块内的成员是私有的,一个模块可以直接访问模块内的成员,子模块可以访问父模块中的成员
1 | // src/module.rs |
使用 pub
关键字将其变为公有
1 | // src/module.rs |
此时,submodule
子模块、Structure
结构体和 foo
函数作为模块内的成员,对外部是可见的,但 submodule
子模块内的成员依然对 submodule
是私有的,若需要外部访问 submodule
子模块内的成员,依然使用 pub
关键字修饰
1 | // src/module.rs |
pub
关键字还可以控制结构体成员和枚举成员的可访问性
-
结构体成员默认为私有的,可以用
pub
修饰变为公有1
2
3
4
5
6
7
8
9
10
11
12
13
14pub struct Breakfast {
pub toast: String,
seasonal_fruit: String, // seasonal_fruit为私有字段
}
impl Breakfast {
// 公有关联函数
pub fn summer(toast: &str) -> Breakfast {
Breakfast {
toast: String::from(toast),
seasonal_fruit: String::from("peaches"),
}
}
} -
枚举成员默认为私有的,一旦枚举类型用
pub
修饰变为公有,则所有成员变为公有1
2
3
4pub enum Appetizer {
Soup,
Salad,
}
引入模块
绝对路径与相对路径
使用 use
关键字引入一个模块或模块成员,在引入时的路径格式为 A::B::C
,有两种形式
-
绝对路径:以根模块
crate
开始1
use crate::module::submodule;
-
相对路径:默认以当前模块开始,
self
关键字表示当前模块,super
关键字表示父模块1
2
3
4// 当前模块为src/module.rs
use submodule::foo; // 对应绝对路径为crate::module::submodule::foo
use self::submodule; // 对应绝对路径为crate::module::submodule
use super::other_module; // 对应绝对路径为crate::other_module
use
关键字
使用 use
引入的惯用做法
-
对于模块中的函数,引入到模块级别
1
2
3
4
5
6
7mod front_house {
pub mod hosting {
pub fn add_waitlist() {}
}
}
use front_house::hosting; // 调用hosting::add_waitlist(); -
对于模块中的类型,引入到成员级别
1
2
3
4
5
6
7mod front_house {
pub mod hosting {
pub struct House;
}
}
use front_house::hosting::House; // 直接使用House类型
use
引入的模块或模块成员只在当前模块中可见
1 | mod front_house { |
若需要外部访问当前模块中引入的模块或模块成员,可以使用 pub use
重导出
1 | pub use front_of_house::hosting; |
当引入发生名称冲突时,使用 as
关键字为某个名称起别名
1 | use std::fmt::Result; |
use
引入支持嵌套路径和通配符
1 | mod front_house { |
注意,在直接路径中,
self
和super
只能用于路径开头,而在嵌套路径中,self
多了一个引入某一级模块本身的功能