写点什么

5 分钟速读之 Rust 权威指南(十一)

用户头像
码生笔谈
关注
发布于: 2021 年 05 月 27 日
5分钟速读之Rust权威指南(十一)

Module

在编写较为复杂的项目时,合理地对代码进行组织与管理很重要,rust 提供了一系列的功能来帮助我们管理代码,包括决定哪些细节是暴露的、哪些细节是私有的,以及不同的作用域内存在哪些名称。

通过定义模块来控制作用域及私有性

在 src 目录下创建 lib.rs 文件,使用 mod 关键字加大括号定义一个模块,可以多层嵌套:


// src/lib.rsmod front_of_house {  // 模块中的内容默认都是隐藏的,需要使用pub将其公开  pub mod hosting {    pub fn add_to_waiting() {}    fn seat_to_table() {}  }  mod serving {    fn take_order() {}    fn serve_order() {    fn take_payment() {}  }}
fn eat_at_restaurant() { // 引用模块内容 // 绝对路径使用crate开头,因为front_of_house是根模块, // 可以理解为绝对路径: /front_of_house crate::front_of_house::hosting::add_to_wait_list();
// 使用相对路径,因为front_of_house和 // eat_at_restaurant在同一级,可以理解为:./front_of_house front_of_house::hosting::add_to_wait_list()}
复制代码

super 关键字

每一个模块是单独的作用域,而且作用域并不会自动向上查找,查找当前模块的上级作用域,可以使用 super:


// back_of_house模块的作用域外部fn serve_order() {}
mod back_of_house { fn cook_order() {}
fn fix_incorrent_order() { // 当前模块作用域中可以直接使用 cook_order();
// 获取父级模块的内容,可是使用super关键字开头,可以理解为:../ super::serve_order() }}
复制代码

公开的结构体

当我们在结构体定义前使用 pub 时,结构体本身就成为了公共结构体,但它的字段依旧保持了私有状态。我们可以逐一决定是否将某个字段公开:


mod back_of_house {  pub struct Breakfast {    // 只公开toast字段    pub toast: String,    // 这个字段仍然是私有的    seasonal_fruit: String,  }
impl Breakfast { pub fn summer(toast: &str) -> Breakfast { Breakfast { toast: String::from(toast), seasonal_fruit: String::from("peaches"), } } }}
pub fn eat_at_restaurant() { let mut meal = back_of_house::Breakfast::summer("Rye");
// 可以访问更改toast属性 meal.toast = String::from("Wheat"); println!("I'd like {} toast please", meal.toast); // I'd like Wheat toast please
// 无法编译通过,因为seasonal_fruit不是公开属性 meal.seasonal_fruit = String::from("blueberries");}eat_at_restaurant();
复制代码

公开的枚举

当我们将一个枚举声明为公共的时,它所有的变体都自动变为了公共状态。我们仅需要在 enum 关键字前放置 pub:


mod back_of_house {  // 对枚举添加pub,会将所有的枚举值公开  pub enum Appetizer {    Soup,    Salad,  }}
pub fn eat_at_restaurant() { let order1 = back_of_house::Appetizer::Soup; let order2 = back_of_house::Appetizer::Salad;}
复制代码

使用 use 关键字引用模块

use 可以引用当前模块中的内容,支持绝对路径和相对路径:


mod front_of_house {  pub mod hosting {    pub fn add_to_wait_list() {}  }}
// 绝对路径方式use crate::front_of_house::hosting; // 方式1use crate::front_of_house::hosting::add_to_wait_list; // 方式2
// 或者相对路径use self::front_of_house2::hosting; // 方式1use self::front_of_house2::hosting::add_to_wait_list; // 方式2
fn eat_at_restaurant() { hosting::add_to_wait_list() // 方式1使用 add_to_wait_list() // 方式2使用}
复制代码

使用 as 关键字对引用模块重命名

当我们引用相同名称的内容会引起冲突,这是需要使用 as 关键字对其中一项进行重命名:


use std::fmt::Result;use std::io::Result as IoResult;
复制代码

重新导出(reexporting)

我们对用户暴露的内容通常需要暴露在一个出口中,这样方便用户导入,


我们需要先将其他的引用导入到同一个模块中,然后重新导出:


pub use crate::front_of_house2::hosting;pub use std::fmt::Result;
复制代码

外部模块

当我们使用第三方模块时,需要先在 cargo.toml 中添加依赖,例如使用一个能够获取随机数的包:


[dependencies]rand = "0.5.5"// 运行 cargo build
复制代码


引入 rand:


use rand::Rng;fn main() {  let secret_number = rand::thread_rng().gen_range(1, 101);}
复制代码


引入标准库中的模块,标准库虽然不用在 toml 中声明,也不用下载,但是也需要显式引入:


use std::collections::HashMap;
复制代码

嵌套批量导入

use std::{cmp::Ordering, io};// 等同于use std::cmp::Ordering;use std::io;
复制代码


使用 self 表示引用导入路径的自身:


use std::io::{self, Write};// 僧同于use std::io;use std::io::Write;
复制代码

使用*运算符导入所有

// 引入collections下面所有的内容use std::collections::*// 直接使用引入的内容BTreeMap::new();
复制代码

将模块拆分到不同的文件

上边的所有例子都是在同一个文件中,我们可以把不同功能的代码拆分到不同的文件中维护,有两种方式可以实现,例如我们要在 lib.rs 中使用如下结构的模块:


// src/lib.rsmod a; // 引入a模块use a::structs::{ A1, A2 }; // 使用a模块中的结构体中的A1,A2结构体
复制代码

方式一

使用模块同名文件夹结构来组织,这种组织方式将一个模块的同名文件夹作为模块的内容,模块本身作为入口文件,首先创建 a.rs 文件作为 a 模块的入口文件:


touch src/a.rs
复制代码


创建 a 模块的同名文件夹,用于放置 a 模块的内容:


mkdir src/a
复制代码


在文件夹 a 中创建结构体模块:


touch src/a/structs.rs
复制代码


创建 A1 和 A2 结构体:


// src/a/structs.rspub struct A1 {}pub struct A2 {}
复制代码


最后在 a 模块的入口文件中引入 structs 模块并向外导出:


// src/a.rspub mod structs;
复制代码


最后结构如下:


src├── a│   └── structs.rs├── a.rs├── lib.rs
复制代码

方式二

使用模块入口放在模块文件夹中的方式来组织,这种方式将文件夹作为模块名称,在文件夹中使用 mod.rs 作为模块入口,首先创建模块文件夹:


mkdir src/a
复制代码


在文件夹 a 中创建结构体模块:


touch src/a/structs.rs
复制代码


创建 A1 和 A2 结构体:


// src/a/structs.rspub struct A1 {}pub struct A2 {}
复制代码


本次不再创建 src/a.rs 文件,而是在文件夹 a 中放置入口文件 mod,名称是固定的,就好像我们在 JS 中一般使用 index.js 如出一辙:


touch src/a/mod.rs
复制代码


在入口文件中引入并导出 a 模块的内容:


// src/a/mod.rspub mod structs;
复制代码


这种方式的目录接否如下:


src├── a│   ├── mod.rs│   └── structs.rs├── lib.rs
复制代码


本章节只介绍了模块的基本用法和两种目录结构的使用方式,更详细的内容可以自行去翻阅原书。

发布于: 2021 年 05 月 27 日阅读数: 7
用户头像

码生笔谈

关注

欢迎关注「码生笔谈」公众号 2018.09.09 加入

前端、Rust干货分享,一起成为更好的Javascripter & Rustacean

评论

发布
暂无评论
5分钟速读之Rust权威指南(十一)