我能否在Rust中“侧向”引入模块?

9
我想把一个Rust程序拆分成多个文件,但使用mod似乎不允许我从除了main.rs以外的文件中引用同一目录下的文件。
例如,如果我在同一个文件夹中有main.rsgame.rsmatrix.rs,我可以通过mod game;mod matrix;main.rs中引用game.rsmatrix.rs中的结构体/函数。然而,我无法使用mod matrix之类的语句从game.rs中引用matrix.rs
我查看了几个资源,它们都只有像树一样的模块结构,彼此之间没有引用。在Rust中是否可以在文件之间使用结构体/函数,或者这违反规则?如果是这样,为什么Rust不允许这样做?

看一下这个答案。这也在教程中有详细讲解。 - Mokosha
https://fasterthanli.me/articles/rust-modules-vs-files - Akshay Naik
1个回答

12

mod模块声明。这个指令声明了一个模块及其所有内容。恰好这些内容可能位于另一个文件中。因此,它看起来像这样:

mod game;
mod matrix;

大致上等同于这个:

mod game {
    // game.rs contents
}

mod matrix {
    // matrix.rs contents
}

自然地,由于 mod 是模块声明,因此您不能为同一个模块多次重复声明。也就是说,您可以尝试编写类似以下的代码:

mod game {
    mod matrix;
    ...
}

mod matrix;

但是,正如您所看到的,matrixgame::matrix 是不同的模块,因此 rustc 需要不同的路径来访问它们各自的文件(如果它们是外部模块)。

use 是一种导入声明use 声明从其他模块中提取名称以在当前模块中使用。您可以从任何地方多次使用任何模块和其中的公共项,只要该模块可访问即可。

因此,为了引用game 中的matrix,您需要use它:

// game.rs
use matrix;

自然而然,为了使这个工作正常,应该在crate根目录中使用mod声明matrix

另外,我个人认为理解Rust模块系统的最简单方法是先忘记模块可以放在不同的文件中。也就是说,将一个crate仅定义在单个文件中。在Rust中,mod指令可以有主体并可以嵌套,因此嵌套的mod实际上定义了crate的模块系统:

mod foo {
    mod bax {
        ...
    }
    mod baz {
        ...
    }
}
mod bar {
    mod qux {
        mod zux {
            ...
        }
    }
}

如果您只有一个单独的文件,您可以轻松地了解moduse指令的工作原理,并且模块之间的关系应该变得清晰明了。

现在您只需要补充一点,即如果模块声明时没有主体,例如mod name;,那么它的内容将从name.rs或者name/mod.rs中加载,以任何一个可用的为准。然而,整个情况没有改变—这些仍然是嵌套模块,可以始终表示为带有嵌套mod指令的单个源文件。事实上,cargo rustc -Z unstable-options --pretty=normal将在外部源文件的所有模块被组装成单个文档后以此形式打印您的crate。我建议您在一些具有复杂模块结构的crate上运行此命令,以查看实际效果。


对于我来说,理解 mod 的含义就像是 C 或 Cpp 的 #include 指令一样,但有一些搜索功能,可以查找名称/模块或 name.rs,不过我可能会忽略一些细节。 - Xavier T.
4
@XavierT. C/C++和Rust之间的两个主要差异是:第一,在Rust中,编译单元比C/C++中大得多(一个crate对应一个或多个.rs文件和一个或多个模块,而一个目标文件只对应一个.c/.cpp文件和文本包含的头文件);第二,在Rust中,模块实际上提供了命名空间和封装,而这在C中不成立,并且在C++中也只有部分成立(其中命名空间确实存在,但并不与编译单元绑定,并且不提供抽象边界)。 - Vladimir Matveev
啊,是的,命名空间也很重要! - Xavier T.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接