在我见过的一些 Rust 项目(即 pczarn/rustboot(中,无论出于何种原因,我都看到了目录中mod.rs
文件。我无法找到有关此的文档,并且在许多其他 Rust 项目中都看到了它。mod.rs 文件的用途是什么,我应该什么时候使用它?
想象一下以下目录结构:
法典/ '——main.rs -东西/ '- mod.rs
如果在main.rs
中你执行mod something;
,那么它将在something/mod.rs
文件中查找以用作something
模块声明的内容。
另一种方法是在 code/
目录中有一个something.rs
文件。
所以回顾一下,当你编写一个空的模块声明,如 mod something;
,它看起来要么:
- 同一目录中名为
something.rs
的文件 - 同一目录中名为
something
的文件夹中名为mod.rs
的文件
然后,它使用其中任一文件的内容用作模块声明的内容。
模块对于理解很重要,但我发现大多数文档经常让你在这个问题上挠头。
来自Python还是Javascript?
粗略地说,mod.rs
有点像python中的__init__.py
或javascript中的index.js
。但只是一种。这在 Rust 中有点复杂。
生锈是不同的
文件夹还没有立即准备好在 Rust 中用作模块。
您必须在文件夹中添加一个名为 mod.rs
的文件,以公开一个名为该文件夹的新模块。mod.rs
中的代码是该模块的内容。文件夹中的所有其他文件可能依次作为子模块公开(更多内容见下文(。
等等,还有另一种方法
您也可以使用与文件夹级别相同的文件,并以该文件夹命名 ( <folder_name>.rs
(。
这是自 rustc 1.30 以来的首选方式。(评论中感谢马库斯托曼(
来自 Rust 参考:
注意:在 rustc 1.30 之前,使用 mod.rs 文件是加载的方式具有嵌套子项的模块。鼓励使用新的命名约定,因为它更一致,并避免了许多项目中名为 mod.rs 的文件。
完整示例
src
utils
bar.rs
foo.rs
main.rs
此时,编译器不知道src/utils/foo.rs
和src/utils/bar.rs
。
首先,您必须公开src/utils/
。如上所示,您有 2 个选项:
- 添加文件:
src/utils/mod.rs
- 添加文件
src/utils.rs
(名称与文件夹完全相同,不带扩展名(
现在,相对于 src 文件夹(又名 crate 级别(,可以使用一个名为 utils
的模块。
其次,您必须公开文件src/utils/foo.rs
并src/utils/bar.rs
。
为此,utils
模块必须声明 2 个以这些文件命名的新子模块。所以src/utils/mod.rs
(或src/utils.rs
(的内容应该是:
pub mod bar;
pub mod foo;
现在,这两个文件中公开的任何内容都可以在其他模块中使用! 🎉
你可以用src/main.rs
写以下内容:
mod utils;
use utils::{foo, bar};
生成的文件结构
选项 1 • mod.rs
(旧方式(:
src
utils
bar.rs
foo.rs
mod.rs
main.rs
选项 2 • <folder_name>.rs
(首选方式(:
src
utils
bar.rs
foo.rs
utils.rs
main.rs
<小时 />
有关模块工作原理的更多高级详细信息
这仍然是一个表面的解释,你的下一个目的地是官方文档 🧑 🎓
还有第三种声明模块(核心语言(的方法:
mod utils {
// module code goes here. That's right, inside of the file.
}
但也有可能只写mod utils;
.在这种情况下,如上所示,Rust 知道搜索src/utils.rs
或src/utils/mod.rs
中的任何一个。
看,当您尝试在文件中使用模块(例如src/main.rs
(,您可以通过以下方式引用它:
- 从内部:
src/main.rs
-
mod module { ... }
-
- 从内部嵌套模块:
src/main.rs
-
mod module { pub mod sub_module { ... } }
-
- 从 sybling 文件:
src/*.rs
- 从
mod.rs
个文件夹中的文件:src/*/mod.rs
- (以及上述的无限递归组合(
包含mod.rs
的文件或文件夹不会成为模块。
相反,Rust 语言允许您使用文件层次结构组织模块(语言功能(。
真正有趣的是,您可以自由地将所有方法混合在一起。
例如,您可能认为不能直接从main.rs
引用src/utils/foo.rs
。
但您可以:
// src/main.rs
mod utils {
pub mod foo;
}
重要提示:
- 在文件中声明的模块将始终优先(因为实际上您永远不需要搜索文件层次结构(
- 您不能使用其他 2 种方法来引用同一模块
例如,同时具有 src/utils.rs
和 src/utils/mod.rs
将在编译时引发以下错误:
error[E0761]: file for module `utils` found at both "src/utils.rs" and "src/utils/mod.rs"
--> src/main.rs:1:1
|
1 | mod utils;
| ^^^^^^^^^^
|
= help: delete or rename one of them to remove the ambiguity
让我们总结一下。模块向编译器公开:
- 从上到下
- 仅供参考(这就是为什么在模块"导入"之前你没有智能感知的原因(
- 从入口点开始(默认情况下
src/main.rs
或src/lib.rs
。但它可能是您在Cargo.toml
中配置的任何内容。然而,这与这个问题关系不大(
通过我们之前的示例,我们按顺序排列:
src/main.rs
->crate
因为
crate
模块包含我们接下来得到mod utils;
:src/utils.rs
或src/utils/mod.rs
->crate::utils
因为
utils
模块包含我们接下来得到的mod foo;
:src/utils/foo.rs
->crate::utils::foo
除了始终与crate
模块匹配的 lib.rs 和 main.rs 之外,每个rs
文件都有自己的模块。
只有一种方法可以声明模块:
/* pub */ mod sub_module1;
模块不能在根/crate 模块树之外声明(即,在模块树中,子模块必须始终具有直接在lib.rs
或main.rs
中声明的父模块,因此第一个程序子模块必须始终在那里声明 - 树数据结构,如果还不够明显(。
有两种方法可以将模块嵌套在声明模块的模块中:
- 在
<module_where_it_is_declared>/<module_name.rs>
- 在
<module_where_it_is_declared>/module_name/mod.rs
如果module_where_it_is_declared
是 crate 模块,则不需要这个相应的子文件夹(从上面的方案中消失(。
下面是一个示例,对 lib 和二进制板条箱都有效:
src
|---lib.rs ( contains: pub mod b2; )
|---b2.rs ( contains: pub mod bb2; )
|---b2
| |---bb2.rs
. .
或者:
src
|---lib.rs ( contains: pub mod b2; )
|---b2
| |---mod.rs ( contains: pub mod bb2; )
| |---bb2.rs
. .
你可以看到你可以混合和匹配(b2使用mod.rs
方式,bb2使用"文件"方式(。
以下是仅使用同样有效的文件模式的方法:
src
|---lib.rs ( contains: pub mod b2; )
|---b2.rs ( contains: pub mod bb2; )
|---b2
| |---bb2.rs (contains: pub mod bbb2; )
| |---bbb2.rs (contains: pub mod bbbb2; )
| |---bbb2
| | |---bbbb2.rs
. . .
我想这取决于你想如何嵌套模块。
我喜欢只导出其他子模块并且其中没有任何其他(或很少(代码的模块的mod.rs
语法,尽管您可以将任何您想要的内容放入mod.rs
.
我使用类似于 JS/TS 世界中的桶模式mod.rs
将多个子模块汇总到单个父模块中。
另外不要忘记,可以通过添加作用域块来内联定义(不仅是声明(模块:
pub mod my_submodule {
// ...
}