模块 Crate¶
模块¶
Rust 中的模块(modules)是用来组织和管理代码的机制。一个模块可以包含函数、结构体、枚举、traits 等。
在 Rust 中,模块使用 mod
关键字来定义,并且可以嵌套。一个模块可以在一个文件中定义,或者分布在多个文件中。
下面是一个简单的例子来说明模块的使用:
mod my_module {
fn private_function() {
println!("This is a private function");
}
pub fn public_function() {
println!("This is a public function");
}
pub mod nested_module {
pub fn nested_function() {
println!("This is a nested function");
}
}
}
fn main() {
my_module::public_function();
// 无法直接调用 private_function,因为它是私有的
// my_module::private_function();
my_module::nested_module::nested_function();
}
在上面的例子中,my_module
是一个模块,它包含了一个私有函数 private_function
和一个公共函数 public_function
。my_module
模块中还定义了一个嵌套模块 nested_module
,它包含了一个公共函数 nested_function
。
在 main
函数中,我们可以通过 my_module::public_function()
直接调用 public_function
。但是,我们无法直接调用 private_function
,因为它是私有的。我们可以通过 my_module::nested_module::nested_function()
调用 nested_function
。
use crate::my_mod::{publ,message};
mod my_mod {
fn pri(a:i32,b:i32) -> i32 {
return a + b;
}
pub fn publ(a:i32,b:i32) ->i32 {
let temp = a * pri(a, b);
return temp;
}
pub struct message {
pub mess:String,
}
impl message {
pub fn say(&self) {
println!("{}",self.mess);
}
}
}
fn main() {
println!("ans is {}",publ(3, 4));
let m = message {
mess:"Hello".to_string(),
};
m.say();
}
use xxxx as yyyy ;
类似于Python中的import xxxx as yyyy
模块、路径、use
关键词和pub
关键词如何在编译器中工作¶
- 从 crate 根节点开始: 当编译一个 crate, 编译器首先在 crate 根文件(通常,对于一个库 crate 而言是_src/lib.rs_,对于一个二进制 crate 而言是_src/main.rs_)中寻找需要被编译的代码。
- 声明模块: 在 crate 根文件中,你可以声明一个新模块;比如,你用
mod garden
声明了一个叫做garden
的模块。编译器会在下列路径中寻找模块代码:- 内联,在大括号中,当
mod garden
后方不是一个分号而是一个大括号 - 在文件 src/garden.rs
- 在文件 src/garden/mod.rs
- 内联,在大括号中,当
- 声明子模块: 在除了 crate 根节点以外的其他文件中,你可以定义子模块。比如,你可能在_src/garden.rs_中定义了
mod vegetables;
。编译器会在以父模块命名的目录中寻找子模块代码:- 内联,在大括号中,当
mod vegetables
后方不是一个分号而是一个大括号 - 在文件 src/garden/vegetables.rs
- 在文件 src/garden/vegetables/mod.rs
- 内联,在大括号中,当
- 模块中的代码路径: 一旦一个模块是你 crate 的一部分,你可以在隐私规则允许的前提下,从同一个 crate 内的任意地方,通过代码路径引用该模块的代码。举例而言,一个 garden vegetables 模块下的
Asparagus
类型可以在crate::garden::vegetables::Asparagus
被找到。 - 私有 vs 公用: 一个模块里的代码默认对其父模块私有。为了使一个模块公用,应当在声明时使用
pub mod
替代mod
。为了使一个公用模块内部的成员公用,应当在声明前使用pub
。 use
关键字: 在一个作用域内,use
关键字创建了一个成员的快捷方式,用来减少长路径的重复。在任何可以引用crate::garden::vegetables::Asparagus
的作用域,你可以通过use crate::garden::vegetables::Asparagus;
创建一个快捷方式,然后你就可以在作用域中只写Asparagus
来使用该类型。
文件结构:
$ tree .
.
├── my
│ ├── inaccessible.rs
│ └── nested.rs
├── my.rs
└── split.rs
In split.rs:
// This declaration will look for a file named `my.rs` and will
// insert its contents inside a module named `my` under this scope
mod my;
fn function() {
println!("called `function()`");
}
fn main() {
my::function();
function();
my::indirect_access();
my::nested::function();
}
In my.rs:
// Similarly `mod inaccessible` and `mod nested` will locate the `nested.rs`
// and `inaccessible.rs` files and insert them here under their respective
// modules
mod inaccessible;
pub mod nested;
pub fn function() {
println!("called `my::function()`");
}
fn private_function() {
println!("called `my::private_function()`");
}
pub fn indirect_access() {
print!("called `my::indirect_access()`, that\n> ");
private_function();
}
In my/nested.rs:
pub fn function() {
println!("called `my::nested::function()`");
}
#[allow(dead_code)]
fn private_function() {
println!("called `my::nested::private_function()`");
}
In my/inaccessible.rs:
#[allow(dead_code)]
pub fn public_function() {
println!("called `my::inaccessible::public_function()`");
}
Let's check that things still work as before:
$ rustc split.rs && ./split
called `my::function()`
called `function()`
called `my::indirect_access()`, that
> called `my::private_function()`
called `my::nested::function()`
File hierarchy - Rust By Example
我们可以通过在路径的开头使用 super
,从父模块开始构建相对路径,而不是从当前模块或者 crate 根开始。这类似以 ..
语法开始一个文件系统路径。