什么是Rust模块
模块是Rust中用于管理代码的结构。模块可以包含函数、常量、枚举、特质、结构体等元素。类似于C++中的命名空间和Python中的模块。我们可以通过使用mod 模块名 {}来创建模块。
创建模块并访问其函数
1. 完整的层级结构必须显式地设置为公共的,例如module_b和fun()。默认情况下,所有内容都是私有的,无法访问。
2. 函数可以通过绝对路径或相对路径来访问。
• 绝对路径:从crate根开始。
• 相对路径:从调用模块的当前作用域开始。//推荐使用
crate
└── module_a
|── module_b
├── fun1
└── fun2
mod module_a {
pub mod module_b {
pub fn fun1() {
print!("fun");
}
fn fun2(){}
}
}
fn main(){
crate::module_a::module_b::fun1(); //绝对路径
module_a::module_b::fun1(); //相对
module_a::module_b::fun2(); //Error, 私有
}
这一种是最简单粗暴的做法,如果你要使用。记得要引入文件,要不代码无法读取正确的module。
super关键字
使用super关键字,我们可以构建从父模块开始的相对路径。这类似于在文件系统路径中使用..语法。
mod module_a {
fn fun_a(){}
pub mod module_b {
fn fun_b(){}
pub mod module_c {
pub fn fun_c() {
print!("fun_c");
}
//super::fun_a(); //无法编译。fun_a()不在父模块module_b中。
super::fun_b(); //fun_b()在父模块module_b中,可以正常调用!
}
}
}
fn main(){
crate::module_a::module_b::module_c::fun_c(); //绝对路径
//module_a::module_b::fun(); //相对路径
}
////////类似于文件系统///////////
crate
└── module_a
├── fun_a
└── module_b <-------
├── fun_b |
└── module_c super可以访问父级(../)
└── fun_c |
└── super ---------
模块内的结构体
1. 要访问结构体,必须将其声明为公共的,但结构体的所有字段默认仍然是私有的。
2. 要访问任何字段,该字段必须被设置为公共的。
3. 我们需要为module_a::st定义一个实现,以便访问其中的字段,因为存在私有成员。
4. 然后我们可以使用点标记法来访问成员。
mod module_a {
pub struct st{ //1
pub a:u32, // 堆代码 duidaima.com
b:u16, //This remains pvt
}
impl test { //3
pub fn fun(x: u32) -> st {
st {
a: x,
b: 10,
}
}//fun
}//test
}//module_a
pub fn fun1 {
let mut var = crate::test::fun(30); //4
println!("{}", var.st.a); //30
println!("{}", var.st.b); //10
}
模块内的枚举
与模块内的结构体不同,如果枚举是公共的,那么它的所有变体也是公共的。这与结构体不同,在结构体中,我们需要显式地将每个枚举变体设置为公共的。
mod module_a {
pub enum Color {
Red, //如果枚举是公共的,所有枚举变体也是公共的
Yellow,
}
}
pub fn fun() {
let var = module_a::Color::Red;
}
use 关键字
类似于C++中的类型别名/using关键字,use 用于将路径引入作用域。
mod module_a {
pub mod module_b {
pub fn fun() {}
}
}
use crate::module_a::module_b;
pub fn fun1() {
module_b::fun(); //现在 module_b 成为一个有效的名称(在 crate 作用域中定义)
}
use as
为路径定义更短的名称。
use std::fmt::Result as FmtResult;
use std::io::Result as IoResult;
fn function1() -> FmtResult {
// --codeing--
}
fn function2() -> IoResult<()> {
// --codeing--
}
pub use / 重新导出
使用 use 关键字将名称引入作用域后,该名称在新作用域中是私有的。要使其可用,我们可以结合 pub 和 use。这种技术称为重新导出,因为我们不仅将项目引入作用域,还使其可供其他人引入他们的作用域。
mod module_a {
pub mod module_b {
pub fn fun() {}
}
}
pub use crate::module_a::module_b;
pub fn fun2() {
module_b::fun();
}
真实案例
如果你的项目结构包含多个文件夹,你可以通过嵌套模块来组织代码。假设我们有以下项目结构:
my_project/
├── Cargo.toml
└── src/
├── main.rs
├── module_a/
│ ├── mod.rs
│ └── sub_module_a.rs
└── module_b/
├── mod.rs
└── sub_module_b.rs
在 main.rs 中,你可以声明模块并使用它们。
// src/main.rs
mod module_a;
mod module_b;
fn main() {
module_a::function_a();
module_b::function_b();
module_a::sub_module_a::sub_function_a();
module_b::sub_module_b::sub_function_b();
}
在 mod.rs 文件中声明子模块
在每个模块文件夹中,创建一个 mod.rs 文件,并在其中声明子模块。例如:
// src/module_a/mod.rs
pub mod sub_module_a;
pub fn function_a() {
println!("Hello from module_a!");
}
// src/module_b/mod.rs
pub mod sub_module_b;
pub fn function_b() {
println!("Hello from module_b!");
}
在子模块文件中定义子模块内容
在子模块文件中定义具体内容。例如:
// src/module_a/sub_module_a.rs
pub fn sub_function_a() {
println!("Hello from sub_module_a!");
}
// src/module_b/sub_module_b.rs
pub fn sub_function_b() {
println!("Hello from sub_module_b!");
}
使用 use 关键字简化路径
你可以使用 use 关键字来简化路径,使代码更简洁:
// src/main.rs
mod module_a;
mod module_b;
use module_a::sub_module_a::sub_function_a;
use module_b::sub_module_b::sub_function_b;
fn main() {
module_a::function_a();
module_b::function_b();
sub_function_a();
sub_function_b();
}
使用 pub use 重新导出
如果你希望在其他模块中使用某个模块的内容,可以使用 pub use 重新导出
// src/module_a/mod.rs
pub mod sub_module_a;
pub use sub_module_a::sub_function_a;
pub fn function_a() {
println!("Hello from module_a!");
sub_function_a();
}
调用的地方
// src/main.rs
mod module_a;
use module_a::sub_function_a;
fn main() {
module_a::function_a();
sub_function_a();
}
通过这种方式,你可以有效地组织和管理Rust项目中的代码,使其更具可读性和可维护性。
结论
模块提供了一种非常简单的方式,将代码分割成有意义的块,每个块可以相互交互或独立存在。