模块化的四个层级
Functions
Modules
:有四种形式- 在文件内,使用
**mod**
定义的内联模块(inline module
) - 2018版本中,一个文件本身就是一个模块,一个和文件同名的文件夹是它的子模块、
- 2015版本中,一个文件夹是一个模块,根模块是
**mod.rs**
,其余文件是它的子模块
- 在文件内,使用
Crates
:有两种形式- 可执行
executable crate
中,位于自身src
下的**lib.rs**
文件 - 在
Cargo.toml
中指定的外部(Dependency
)crate
:- 通过文件路径(
Path
)指定 - 通过
git
地址指定 - 通过
Crates.io
中的crate
名指定
- 通过文件路径(
- 可执行
Workspaces
- 在同一个文件夹下管理多个
crates
- 在同一个文件夹下管理多个
结构体和枚举
结构体的所有字段默认私有,即使结构体前有pub
关键字,也需要在字段前单独加**pub**
关键字,另外需要为这样的结构体配一个关联函数来初始化实例
当枚举前加上pub
关键字时,枚举的所有字段也成为公有的,可以直接使用
Modules
模块路径
绝对路径:从模块根开始,即从crate
开始往下写
相对路径:使用self
从当前模块开始,使用super
从父模块开始
内联模块
- 默认情况下,模块中的内容都是私有的
- 使用
pub
关键字使其外部可访问
示例:
fn main() {
greetings::hello();
}
mod greetings {
// ⭐️ 默认情况下,模块中的内容都是私有的
pub fn hello() { // ⭐️ 使用pub关键字使其外部可访问
println!("Hello, world!");
}
}
私有函数能够被当前模块和子模块调用:
self
引用模块自己super
引用父模块
示例:
// 1.调用模块自身的私有方法
fn main() {
phrases::greet();
}
mod phrases {
pub fn greet() {
hello(); // 或者使用 `self::hello();`
}
fn hello() {
println!("Hello, world!");
}
}
// 2.调用父模块的私有方法
fn main() {
phrases::greetings::hello();
}
mod phrases {
fn private_fn() {
println!("Hello, world!");
}
// 定义子模块
pub mod greetings {
pub fn hello() {
// 调用父模块私有方法
super::private_fn();
}
}
}
文件即模块
- 引用相同文件夹下的文件模块:
示例:
// ↳ main.rs
mod greetings; // 导入greetings模块
fn main() {
greetings::hello();
}
// ↳ greetings.rs
// ⭐️ 不用使用mod定义,因为文件本身就是一个模块
pub fn hello() {
println!("Hello, world!");
}
文件模块与子模块
2015和2018的对比:
在2015版本中,要么用foo.rs
,要么用foo/mod.rs
定义模块,如果foo
有子模块,那么必须用第二种方式
在2018版本中,foo.rs
的子模块被放在foo/
下
2015版本用法
mod.rs in the directory module root is the entry point to the directory module. All other files in that directory root, act as sub-modules of the directory module.
mod.rs
是文件夹模块的入口点- 文件夹下的所有其他文件模块是文件夹模块的子模块
2018版示例
- 同级模块/文件可以直接使用
- 再下级的子模块需要声明pub
模块树:
- 写在一起的情况 ```rust // 父作用域 // 即 crate 作用域下 fn main() { // 可以直接使用同级的模块 a::hello(); // 同级模块下的子模块需要使用pub声明 a::b::world(); }
mod a { // a作用域下 pub fn hello() { println!(“Hello”) }
// 子模块需要暴露,才能被父作用域下的main使用
pub mod b {
pub fn world() {
println!("world")
}
}
}
2. 使用模块文件的情况
```rust
// ↳ main.rs
// crate的作用域下
// 声明使用同级的a模块
mod a;
fn main() {
a::hello();
a::b::world();
}
// a模块
// a的作用域下
// ↳ a.rs
pub mod b; // 二次导出 b 模块
pub fn hello() {
println!("Hello")
}
// b模块
// ↳ a / b.rs
pub fn world() {
println!("world")
}
Crates
Crates are a bit similar to the packages in some other languages. Crates compile individually. (cargo package) If the crate has child file modules, those files will get merged with the crate file and compile as a single unit.
A crate can produce an executable/ a binary or a library. src/main.rs is the crate root/ entry point for a binary crate src/lib.rs is the entry point for a library crate.
Crate
分为两种“
binary crate
,入口点:src/main.rs
library crate
,入口点:src/lib.rs
src/main
是二进制crate
的根,src/lib
是库crate
的根,在模块树中,它们就是根模块,叫做**crate**
:
在binary crate
中使用lib.rs
、
常用的模式:可以在lib.rs
中写功能,然后在main.rs
中引用lib.rs
示例:
在main.rs
中使用extern crate <project_name>
语句来引入lib.rs
,
在lib.rs
中暴露其他文件模块
// # 文件结构
phrases
├── Cargo.toml
└── src
├── greetings.rs
├── lib.rs
└── main.rs
// 02. phrases/src/main.rs
extern crate phrases; // 引用lib.rs
fn main() {
phrases::greetings::hello();
}
// 03. phrases/src/lib.rs
pub mod greetings; // 暴露其他文件模块
// 01. phrases/src/greetings.rs
pub fn hello() {
println!("Hello, world!");
}
引入外部Crates
- 通过相对路径引入
[dependencies]
greetings = { path = "greetings" }
- 通过
git
地址引入
[dependencies]
rocket = { git = "https://github.com/SergioBenitez/Rocket" }
- 通过
Crates.io
名称引入
[dependencies]
test_crate_hello_world = "0.1.0"
Workspaces
Workspaces
用来在一个项目里管理多个crates
Rust uses a shared build directory under the project root, while running cargo build from the project root.
运行cargo build
的时候,Rust
把多个crates
编译好的依赖放到**shared build directory**
中,避免了为每个**crate**
生成重复的依赖
在project
的任何目录下运行cargo
命令,等同于在project root
下运行命令,避免了切换当前目录
Use关键字
- 使用
use
关键字能简化模块的引入写法,可以使用**as**
来指定别名 Re-exporting
,二次暴露
Rust
中默认所有项(函数、方法、结构体、枚举、模块和常量)都是私有的。
父模块中的项不能使用子模块中的私有项,但是子模块中的项可以使用他们父模块中的项。
使用 *
(glob 运算符)可以将此模块下的所有公有项引入作用域
preludes
Even some modules inside std crate (ex.std::io) and many libraries (ex. Diesel) are having their own prelude modules.
一些std
库和第三方库有自己的prelude
模块
But preludes are used to create a single place to import all important components which are required while using the library. They do not load automatically unless you imported them manually. Only std::prelude imports automatically in every Rust programs.
preludes
是用来导入外部库中重要组件的一个地方
这些preludes
需要手动加载
只有**std::prelude**
会自动加载