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 声明默认私有```rustmod 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 privateprintln!("{}", mod1::mod2::MESSAGE); // mod2 如果不加 pub 也会报错println!("{}", mod1::Alphabet::A as u8); // 1mod1::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 绑定模块成员- 用于简化方法访问路径```rustuse 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.rspub const MESSAGE: &str = "mod1 message";// main.rsmod mod1;fn main() {println!("{}", mod1::MESSAGE);}
将模块映射到文件夹
src|- main.rs|- mod1|- mod1_a.rs|- mod.rs
// mod1/mod.rspub mod mod1_a;pub const MESSAGE: &str = "mod message";// mod1/mod1_a.rspub const MESSAGE: &str = "mod1_a message";// main.rsmod mod1;fn main() {println!("{}", mod1::mod1_a::MESSAGE);println!("{}", mod1::MESSAGE);}
