[rust 基础知识] rust 模块管理中的 mod 和 use
一、背景
在学习 rust 模块管理的时候,会有两个关键词,mod 和 use,区分清楚这两个关键词,才正确的使用,而不是一遍又一遍地在编译后修复报错。并且本文只区分 mod 和 use,crate 和 super 等关键词,就不解释了。
下面是自己的个人理解。假定初始化项目的文件结构是:
- Cargo.toml
- src/
- main.rs
一、 mod 关键词
rust 使用 mod 关键词用来定义模块和引入模块。
1.1 定义模块
以 mod 关键字为起始,然后指定模块的名字,并且用大括号包围模块的主体。
// src/main.rs
mod add {
pub mod add_one {
pub fn add_one (base: u32) -> u32 {
base + 1
}
}
}
fn main() {
print!("{}", add::add_one::add_one(0));
}
该示例的模块树为:
- crate
- mod add
- mod add_one
- fn add_one
- fn main
1.2 引入模块
使用 mod 组织的模块树结构,可以利用文件结构的目录树形式进行拆分,每个文件或者文件夹就是一个模块。然后以 mod 关键字为起始,然后指定模块的名字,来引入内容。
可以理解成,mod 引入模块,就是将拆分的内容整合后再次放入 main.rs 中。
1.2.1 拆分方式一:拆分成文件
文件结构为:
- Cargo.toml
- src/
- add.rs
- main.rs
文件内容为:
// src/add.rs
pub mod add_one {
pub fn add_one (base: u32) -> u32 {
base + 1
}
}
// src/main.rs
mod add;
fn main() {
print!("{}", add::add_one::add_one(0));
}
在这个示例中,src/add.rs 就是 mod add。
1.2.2 拆分方式二:拆分成文件夹
文件结构为:
- Cargo.toml
- src
- add/
- add_one.rs
- mod.rs
- main.rs
文件内容为:
// src/add/add_one.rs
pub fn add_one (base: u32) -> u32 {
base + 1
}
// src/add/mod.rs
pub mod add_one;
// src/main.rs
mod add;
fn main() {
print!("{}", add::add_one::add_one(0));
}
在这个示例中,src/add/mod.rs 就是 mod add,src/add/add_one.rs 就是 mod add_one。
1.2.3 拆分方式三:拆分成文件加文件夹
文件结构为:
- Cargo.toml
- src
- add/
- add_one.rs
- add.rs
- main.rs
文件内容为:
// src/add/add_one.rs
pub fn add_one (base: u32) -> u32 {
base + 1
}
// src/add.rs
pub mod add_one;
// src/main.rs
mod add;
fn main() {
print!("{}", add::add_one::add_one(0));
}
在这个示例中,src/add.rs 就是 mod add,src/add/add_one.rs 就是 mod add_one。
二、 use 关键词
rust 使用 use 关键词用来调整模块内容调用路径。
这里就要对 mod 和 use 进行区分:use 仅仅是在存在模块的前提下,调整调用路径,而没有引入模块的功能,引入模块使用 mod。
先简单看一下,use 的使用:
mod add {
pub mod add_one {
pub fn add_one (base: u32) -> u32 {
base + 1
}
}
}
use add::add_one;
fn main() {
print!("{}", add_one::add_one(0));
}
通过 use 调整之后,不必每次使用都要写出完整的调用路径了。
三、子模块之间相互调用
项目的文件结构是:
- Cargo.toml
- src/
- add.rs
- equal.rs
- main.rs
文件内容为:
// src/add.rs
use super::equal::equal_one;
pub mod add_one {
pub fn add_one (base: u32) -> u32 {
base + 1
}
pub fn add_one_then_equal_one (base: u32) -> bool {
super::equal_one::equal_one(add_one(base))
}
}
// src/equal.rs
pub mod equal_one {
pub fn equal_one (base: u32) -> bool {
base == 1
}
}
mod add;
use add::add_one;
fn main() {
print!("{}", add_one::add_one_then_equal_one(0));
}
现在这个例子运行是报错的,会提示 use of undeclared crate or module equal。这是因为 add.rs 中通过 use 调整了 equal 模块的引入路径,但是 equal 模块现在还不存在。
按照理解,虽然内容进行了拆分,但是还会整合的,所以整合之后的 main.rs 内容应该理解成是(通过将拆分的内容复原来查找问题):
mod add {
use super::equal::equal_one;
mod add_one {
pub fn add_one;
pub fn add_one_then_equal_one;
}
}
use add::add_one;
fn main;
在通过 use super::equal::equal_one 调整路径时,super 将路径指到了顶层,缺少 equal 模块,所以我们使用 mod 关键词引入即可,调整 main.rs 的内容:
mod add;
mod equal;
use add::add_one;
fn main() {
print!("{}", add_one::add_one_then_equal_one(0));
}
运行成功,可以实现子模块之间相互调用。