Rust 模块系统的清晰解释
本文为转载内容,由Google翻译生成,原文https://www.sheshbabu.com/posts/rust-module-system/
Rust 的模块系统令人惊讶地令人困惑并给初学者带来了很多挫败感。
在这篇文章中,我将使用实际示例解释模块系统,以便您清楚地了解其工作原理并可以立即开始在您的项目中应用它。
由于 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
我们就认为这些文件是modules
,并且可以从其他文件中导入它们。
以下是我们看到的内容(文件系统树)和编译器看到的内容(模块树):
令人惊讶的是,编译器只看到crate
即我们的main.rs
文件模块。这是因为我们需要在 Rust 中显式构建模块树 - 文件系统树到模块树之间没有隐式映射。
我们需要在 Rust 中明确构建模块树,没有隐式映射到文件系统
要将文件添加到模块树中,我们需要使用关键字将该文件声明为子模块mod
。接下来让人感到困惑的是,你会认为我们在同一个文件中将文件声明为模块。但我们需要在另一个文件中声明它!因为我们只main.rs
在模块树中,所以我们config.rs
在中将其声明为子模块main.rs
。
mod 关键字声明一个子模块 该mod关键字的语法如下:
mod my_module;
在这里,编译器在同一目录中寻找my_module.rs
或my_module/mod.rs
my_project
├── Cargo.toml
└─┬ src
├── main.rs
└── my_module.rs
or
my_project
├── Cargo.toml
└─┬ src
├── main.rs
└─┬ my_module
└── mod.rs
由于main.rs
和config.rs
位于同一目录中,因此我们声明配置模块如下:
// main.rs
+ mod config;
fn main() {
+ config::print_config();
println!("main");
}
// config.rs
fn print_config() {
println!("config");
}
我们正在print_config使用::语法访问该函数。
模块树如下所示:
我们成功声明了config
模块!但这还不足以调用print_config
模块内部的函数config.rs
。
Rust中的几乎所有内容默认都是私有的,我们需要使用pub
关键字将函数公开:
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");
}
正如我们前面讨论的,我们只能在同一个目录中使用mod关键字。my_module.rs my_module/mod.rs
因此,为了调用routes/health_route.rs
来自内部的函数main.rs
,我们需要做以下事情:
- 创建一个名为的文件
routes/mod.rs
并routes
在其中声明子模块main.rs
- 声明
health_route
子模块routes/mod.rs
并将其公开 - 将内部函数
health_route.rs
公开
my_project
├── Cargo.toml
└─┬ src
├── main.rs
├── config.rs
├─┬ routes
+ │ ├── mod.rs
│ ├── health_route.rs
│ └── user_route.rs
└─┬ models
└── user_model.rs
// main.rs
mod config;
+ mod routes;
fn main() {
+ routes::health_route::print_health_route();
config::print_config();
println!("main");
}
// routes/mod.rs
+ pub mod health_route;
// routes/health_route.rs
- fn print_health_route() {
+ pub fn print_health_route() {
println!("health_route");
}
模块树如下所示:
我们现在可以调用文件夹内的文件中定义的函数。