模块层级
多文件模块的层级关系
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)。
