Rust 的模块
- 如何使用模块在文件和文件夹中组织代码
- 模块成员的可见性
- 在 crates.io 上发布代码
Rust 的模块化编程
Rust代码组织的基本概念
- Package:包
- Crate:箱
- Module:模块
Package
- 用于管理一个 or 多个 Crate,Package 里最少有一个 Crate
- 使用
cargo new <name>
创建一个 Package 包含的文件:- 必须包含:cargo.toml
- 默认情况 src/main.rs: 是与Package同名的二进制Crate的入口文件
- 因此,现在我们有一个
Package 以及一个 Crate - 同样,create new 带上 —lib,那么 src/lib.rs 将是它的入口文件,且它是一个库 Crate
- 如果src目录中同时包含 main.rs 和 lib.rs ,那么我们将在Package中同时得到一个二进制Crate和一个库Crate
- 这在开发一些基础库的时候很有用
- 例如:用Rust实现了一个函数,既希望这个函数作为库被别人使用,又想获得一个可以进行这个函数计算的命令行工具
Crate
- 是 Rust 的最小编译单元
- Crate 在一个范围内将相关功能组合在一起
- 并通过最终编译生成一个二进制或者库文件
- 一个 Crate 里有 0 或多个 Module
Module
- 允许我们将 Crate 中的代码组织成独立的代码块,增强可读性和复用性
- Module 还控制代码可见性:将代码分为公有和私有代码
- 公有代码可以在项目外被使用
- 私有代码项目内部的代码才可以访问
- 定义一个模块最基本的方式是使用mod关键字
```rust
mod mod1 {
pub mod mod2 {
} }pub const MESSAGE: &str = "mod2 message";
fn main() { println!(“{}”, mod1::mod2::MESSAGE); }
<a name="kiFOJ"></a>
#
<a name="FrEwp"></a>
# 可见性
- Rust 中模块内部的代码,结构体,函数等类型默认是私有的
- 但是可以通过 pub 关键字来改变它们的可见性
- 可以选择性地对外可见来隐藏模块内部的实现细节
<a name="fn05I"></a>
## 常用的三种 pub 写法
- pub:成员对模块可见
- pub(self):成员对模块内的子模块可见
- pub(crate):成员对整个 crate 可见
- 不使用 pub 声明默认私有
```rust
mod mod1 {
// 不加 pub(self) 也可以在mod2::say里访问
// 所以 pub(self) 其实是一个偏标记性质的语法,是给编码者看的
const MESSAGE: &str = "mod1 message without pub";
pub(crate) enum Alphabet {
A = 1,
B = 2,
C = 3,
}
pub mod mod2 {
pub const MESSAGE: &str = "mod2 message with pub";
pub fn say() {
println!("{}", super::MESSAGE);
}
}
}
fn main() {
// println!("{}", mod1::MESSAGE); // error[E0603]: constant `MESSAGE` is private
println!("{}", mod1::mod2::MESSAGE); // mod2 如果不加 pub 也会报错
println!("{}", mod1::Alphabet::A as u8); // 1
mod1::mod2::say(); // mod1 message without pub
}
结构体的可见性
- 结构体的字段和方法默认私有
- 加上 pub,可以在定义结构体的模块之外可访问
⚠️:与结构体同一个模块的代码访问结构体中的字段和方法并不要求pub ```rust mod mod1 { pub struct Person {
name: String,
pub nickname: String,
}
impl Person {
pub fn new(name: &str, nickname: &str) -> Self {
Person {
name: String::from(name),
nickname: String::from(nickname),
}
}
pub fn say_name(&self) {
println!("{}", self.name);
}
} }
fn main() {
let p = mod1::Person::new(“mike”, “mikeNickname”);
p.say_name();
println!(“{}”, p.nickname);
// println!(“{}”, p.name); // error[E0616]: field name
of struct Person
is private
}
<a name="OJdry"></a>
#
<a name="cJ4Sr"></a>
# 使用 use 绑定模块成员
- 用于简化方法访问路径
```rust
use std::fs; // 可以和as一起用:use std::fs as stdfs;
fn main() {
let data = fs::read("src/main.rs").unwrap(); // unwrap 让result中包含错误时,程序直接崩溃
println!("{}", String::from_utf8(data).unwrap());
}
使用 super 和 self 简化模块路径
- 出了使用完整路径访问模块内部成员,还可以用super与self关键字相对路径对模块进行访问
- super: 上层模块
- self:当前模块
- 当上层、当前、子模块中拥有相同名字成员时,使用super和self可以消除歧义 ```rust fn func() { println!(“func called”); }
pub mod mod1 { pub fn func() { super::func(); } pub mod mod2 { fn func() { println!(“mod1::mod2::func called”) }
pub fn call() {
self::func();
}
}
}
fn main() { mod1::func(); mod1::mod2::call(); }
<a name="Jqgxy"></a>
## <br />
<a name="khIEH"></a>
# 项目目录层次结构
<a name="W7n4C"></a>
## 将模块映射到文件
src |- main.rs |- mod1.rs
```rust
// mod1.rs
pub const MESSAGE: &str = "mod1 message";
// main.rs
mod mod1;
fn main() {
println!("{}", mod1::MESSAGE);
}
将模块映射到文件夹
src
|- main.rs
|- mod1
|- mod1_a.rs
|- mod.rs
// mod1/mod.rs
pub mod mod1_a;
pub const MESSAGE: &str = "mod message";
// mod1/mod1_a.rs
pub const MESSAGE: &str = "mod1_a message";
// main.rs
mod mod1;
fn main() {
println!("{}", mod1::mod1_a::MESSAGE);
println!("{}", mod1::MESSAGE);
}