06-将目录用作模块
2.2.3 将目录用作模块
我们还可以创建一个目录来表示模块。这种方法允许我们将模块中的子模块作为文件和目录的层次结构。假设我们有一个目录my_program,它有一个名为foo的模块,并且对应的文件名为foo.rs。它包含一个名为Bar的类型和foo的函数。随着时间的推移,Bar的API数量不断增加,我们希望将它们作为子模块进行分离。可以使用基于目录的模块对此用例进行建模。
为了演示将目录用作模块,我们在名为my_program的目录中创建了一个程序。它在main.rs中有一个入口点,以及一个名为foo的目录。该目录现在包含一个名为bar.rs的子模块。
以下是my_program目录的结构:
+ my_program
└── foo/
└── bar.rs
└── foo.rs
└── main.rs
为了让Rust识别bar,我们需要在目录foo/旁边创建一个名为foo.rs的兄弟文件。foo.rs文件将包含目录foo/中创建的任何子模块的模块声明(此处为bar.rs)。
我们的bar.rs中包含以下内容:
// my_program/foo/bar.rs
pub struct Bar;
impl Bar {
pub fn hello() {
println!("Hello from Bar !");
}
}
我们有一个单位结构体bar,以及关联方法hello(),同时希望在main.rs中使用该API。
注意:在较旧的Rust 2015中,子模块不要求foo文件夹和兄弟文件foo.rs一同出现,而是使用foo中的mod.rs文件向编译器传达该目录是模块。Rust 2018支持这两种方法。
接下来,我们向foo.rs中添加以下代码:
// my_program/foo.rs
mod bar;
pub use self::bar::Bar;
pub fn do_foo() {
println!("Hi from foo!");
}
我们添加了模块bar的声明,然后从模块bar中重新导出Bar的元素。这要求将Bar定义为公有的(pub)。使用关键字pub的部分是从子模块重新导出的元素得以在父模块调用的原因。这里,我们使用关键字self来引用当前模块自身。在编写use语句时,重新导出是一个简便的步骤,这有助于在导入隐藏在嵌套子模块中的元素时消除混乱。
self是相对导入的关键字。虽然鼓励使用crate进行绝对导入,但是在从父模块中的子模块重新导出元素时,使用self的表述更清晰。
最后,main.rs将能够使用这两个模块:
// my_program/main.rs
mod foo;
use foo::Bar;
fn main() {
foo::do_foo();
Bar::hello();
}
我们的main.rs声明了foo,然后导入结构体Bar,接下来我们就可以从foo调用do_foo方法,并在Bar上调用hello。
和模块有关的内容不止目前介绍的这些,我们将在第7章深入介绍它们的细节。介绍完模块之后,接下来我们将讨论Cargo和程序库。