模块层级
多文件模块的层级关系
Rust 的模块支持层级结构,但这种层级结构本身与文件系统目录的层级结构是解耦的。mod xxx;
这个 xxx
不能包含 ::
号。也即在这个表达形式中,是没法引用多层结构下的模块的。也即,你不可能直接使用 mod a::b::c::d;
的形式来引用 a/b/c/d.rs
这个模块。那么,Rust 的多层模块遵循如下两条规则:
-
优先查找
xxx.rs
文件main.rs
、lib.rs
、mod.rs
中的mod xxx;
默认优先查找同级目录下的xxx.rs
文件;- 其他文件
yyy.rs
中的mod xxx;
默认优先查找同级目录的yyy
目录下的xxx.rs
文件;
-
如果
xxx.rs
不存在,则查找xxx/mod.rs
文件,即xxx
目录下的mod.rs
文件。
上述两种情况,加载成模块后,效果是相同的。Rust 就凭这两条规则,通过迭代使用,结合 pub 关键字,实现了对深层目录下模块的加载;
src
├── a
│ ├── b
│ │ ├── c
│ │ │ ├── d.rs
│ │ │ └── mod.rs
│ │ └── mod.rs
│ └── mod.rs
└── main.rs
a/b/c/d.rs
文件内容:
pub fn print_ddd() {
println!("i am ddd.");
}
a/b/c/mod.rs
文件内容:
pub mod d;
a/b/mod.rs
文件内容:
pub mod c;
a/mod.rs
文件内容:
pub mod b;
main.rs
文件内容:
mod a;
use self::a::b::c::d;
fn main() {
d::print_ddd();
}
// i am ddd.
至于为何 Rust 要这样设计,有几下几个原因:
- Rust 本身模块的设计是与操作系统文件系统目录解耦的,因为 Rust 本身可用于操作系统的开发;
- Rust 中的一个文件内,可包含多个模块,直接将
a::b::c::d
映射到a/b/c/d.rs
会引起一些歧义; - Rust 一切从安全性、显式化立场出发,要求引用路径中的每一个节点,都是一个有效的模块,比如上例,
d
是一个有效的模块的话,那么,要求c, b, a
分别都是有效的模块,可单独引用。
模块路径
一个 crate 是一个独立的可编译单元。它有一个入口文件,这个入口文件是这个 crate(里面可能包含若干个 module)的模块根路径。整个模块的引用,形成一个链,每个模块,都可以用一个精确的路径(比如:a::b::c::d
)来表示;与文件系统概念类似,模块路径也有相对路径和绝对路径的概念。为此,Rust 提供了 self 和 super 两个关键字。
self
在路径中,有两种意思:
use self::xxx
表示,加载当前模块中的xxx
。此时 self 可省略;use xxx::{self, yyy}
,表示,加载当前路径下模块xxx
本身,以及模块xxx
下的yyy
;
super
表示,当前模块路径的上一级路径,可以理解成父模块。use super::xxx;
表示引用父模块中的 xxx
。
fn function() {
println!("called `function()`");
}
mod cool {
pub fn function() {
println!("called `cool::function()`");
}
}
mod my {
fn function() {
println!("called `my::function()`");
}
mod cool {
pub fn function() {
println!("called `my::cool::function()`");
}
}
pub fn indirect_call() {
// Let's access all the functions named `function` from this scope!
print!("called `my::indirect_call()`, that\n> ");
// The `self` keyword refers to the current module scope - in this case `my`.
// Calling `self::function()` and calling `function()` directly both give
// the same result, because they refer to the same function.
self::function();
function();
// We can also use `self` to access another module inside `my`:
self::cool::function();
// The `super` keyword refers to the parent scope (outside the `my` module).
super::function();
// This will bind to the `cool::function` in the *crate* scope.
// In this case the crate scope is the outermost scope.
{
use crate::cool::function as root_function;
root_function();
}
}
}
fn main() {
my::indirect_call();
}
另外,还有一种特殊的路径形式:::xxx::yyy
它表示,引用根路径下的 xxx::yyy
,这个根路径,指的是当前 crate 的根路径。路径中的 *
符号:use xxx::*;
表示导入 xxx
模块下的所有可见 item(加了 pub 标识的 item)。