原文链接: http://www.sheshbabu.com/posts/rust-module-system/
原文标题: Clear explanation of Rust’s module system
公众号: Rust碎碎念
翻译: Praying
Rust的模块(module)系统相当令人困惑,这也给很多初学者带来了挫败感。
在本文中,我将会通过实际的例子来解释模块系统以便于让你清晰地理解它是怎样工作的并且能够快速在自己的项目中应用。
由于Rust的模块系统比较独特,我希望读者以开放性思维来进行阅读,并且尽量不要将其与其他语言中的模块的工作方式进行比较。
让我们使用下面的文件结构来模拟一个真实世界中的项目:
my_project
├── Cargo.toml
└─┬ src
├── main.rs
├── config.rs
├─┬ routes
│ ├── health_route.rs
│ └── user_route.rs
└─┬ models
└── user_model.rs
下面是一些使用我们的模块的不同方式:
下面的3个例子应该足以解释Rust的模块系统是如何工作的。
示例1
让我们从第一个例子开始 —— 在main.rs
中导入config.rs
。
// main.rs
fn main() {
println!("main");
}
// config.rs
fn print_config() {
println!("config");
}
很多人常犯的第一个错误是因为我们有像config.rs
,health_route.rs
这样的文件,所以我们就认为这些文件就是模块(module)
且可以在其他的文件中将其导入。
下面是从我们的视角(文件系统树(file system tree))看到的内容和从编译器的角度(模块树(module tree))看到的内容:
令人惊奇,编译器只看到了crate
模块,也就是我们的main.rs
文件。这是因为我们需要显式地在Rust中构建模块树——在文件系统树和模块树之间不存在隐式的转换。
我们需要显式地在Rust中构建模块树——在文件系统树和模块树之间不存在隐式的转换。
想要把一个文件添加到模块树中,我们需要使用mod
关键字来将这个文件声明为一个子模块(submodule)。另一件使人们感到困惑的事情是你会认为在相同的文件里把一个文件声明为模块(译者注:比如使用mod关键字把config.rs声明为子模块,你可能认为需要在config.rs里来写声明)。但是我们需要在一个不同文件里进行声明!因为我们在这个模块树里只有main.rs
这个文件,所以要在main.rs
里将config.rs
声明为一个子模块。
mod 关键字声明一个子模块
mod
关键字语法如下:
mod my_module;
这里,编译器在相同的目录下查找my_module.rs
或者my_module/mod.rs
。
my_project
├── Cargo.toml
└─┬ src
├── main.rs
└── my_module.rs
或者
my_project
├── Cargo.toml
└─┬ src
├── main.rs
└─┬ my_module
└── mod.rs
因为main.rs
和config.rs
在相同的目录下,让我们按照下面的代码声明config模块
// main.rs
+ mod config;
fn main() {
+ config::print_config();
println!("main");
}
// config.rs
fn print_config() {
println!("config");
}
这里,我们通过::
语法使用print_config
函数。
下面是模块树的样子:
我们已经成功地声明了config
模块!但是这还不能调用config.rs
里的print_config
函数。几乎Rust里面的一切默认都是私有(private)的,我们需要使用pub
关键字来让这个函数成为公开(public)的:
pub关键字使事物公开
// main.rs
mod config;
fn main() {
config::print_config();
println!("main");
}
// config.rs
- fn print_config() {
+ pub fn print_config() {
println!("config");
}
现在,这样可以正常工作了。我们已经成功的调用了定义在另一个文件里的函数!
示例2
让我们尝试在main.rs
中调用定义在routes/health_route.rs
里的print_health_route
函数。
// main.rs
mod config;
fn main() {
config::print_config();
println!("main");
}
// routes/health_route.rs
fn print_health_route() {
println!("health_route");
}
正如我们之前所讨论的,我们只能对相同目录下的my_module.rs
或者my_module/mod.rs
使用mod
关键字。
所以为了能够在main.rs
中调用routes/health_route.rs
里定义的函数,我们需要做下面的事情:
创建一个名为 routes/mod.rs
的文件并且在main.rs
中声明routes
子模块
请发表评论