模块层级

多文件模块的层级关系

Rust 的模块支持层级结构,但这种层级结构本身与文件系统目录的层级结构是解耦的。mod xxx; 这个 xxx 不能包含 :: 号。也即在这个表达形式中,是没法引用多层结构下的模块的。也即,你不可能直接使用 mod a::b::c::d; 的形式来引用 a/b/c/d.rs 这个模块。那么,Rust 的多层模块遵循如下两条规则:

  1. 优先查找 xxx.rs 文件

    1. main.rslib.rsmod.rs 中的 mod xxx; 默认优先查找同级目录下的 xxx.rs 文件;
    2. 其他文件 yyy.rs 中的 mod xxx; 默认优先查找同级目录的 yyy 目录下的 xxx.rs 文件;
  2. 如果 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)。

上一页
下一页