前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Rust中使用模块组织代码

Rust中使用模块组织代码

作者头像
端碗吹水
发布于 2022-06-01 01:08:41
发布于 2022-06-01 01:08:41
59100
代码可运行
举报
运行总次数:0
代码可运行

[TOC]


Rust中的模块化编程

自上个世纪 90 年代以来,软件工程的复杂性越来越高,程序渐渐从一个人的独狼开发转为多人团队协作开发。在今天,通过 Github 或中心化的代码分发网站,我们可以轻松的在一个软件工程中同时引入世界各地的开发者开发的代码,我们与同事在同一个工程目录下并行开发不同的程序功能,或者在不拷贝代码的前提下将一个工程中的代码在另一个工程中复用。这一切都是因为模块化编程。

模块化编程,是强调将计算机程序的功能分离成独立的和可相互改变的“模块”的软件设计技术,它使得每个模块都包含着执行预期功能的一个唯一方面所必需的所有东西,复杂的系统被分割为小块的独立代码块。

Rust 项目的代码组织包含以下三个基本概念:

  • Package(包)
  • Crate(箱)
  • Module(模块)

Package

Package 用于管理一个或多个 Crate。创建一个 Package 的方式是使用 cargo new,我们来看看一个 Package 包含哪些文件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ cargo new my-project
     Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs

当我们输入命令时,Cargo 创建了一个目录以及一个 Cargo.toml 文件,这就是一个 Package。默认情况下,src/main.rs 是与 Package 同名的二进制 Crate 的入口文件,因此我们可以说我们现在有一个 my-project Package 以及一个二进制 my-project Crate。同样,如果在创建 Package 的时候带上 --lib,那么 src/lib.rs 将是它的 Crate 入口文件,且它是一个库 Crate。

如果我们的 src 目录中同时包含 main.rslib.rs,那么我们将在这个 Package 中同时得到一个二进制 Crate 和一个库 Crate,这在开发一些基础库时非常有用,例如你使用 Rust 中实现了一个 MD5 函数,你既希望这个 MD5 函数能作为库被别人引用,又希望你能获得一个可以进行 MD5 计算的命令行工具:那就同时添加 main.rslib.rs 吧!

Crate

Crate 是 Rust 的最小编译单元,即 Rust 编译器是以 Crate 为最小单元进行编译的。Crate 在一个范围内将相关的功能组合在一起,并最终通过编译生成一个二进制或库文件。例如,我们在上一章中实现的猜数字游戏就使用了 rand 依赖,这个 rand 就是一个 Crate,并且是一个库的 Crate。

Module

Module 允许我们将一个 Crate 中的代码组织成独立的代码块,以便于增强可读性和代码复用。同时,Module 还控制代码的可见性,即将代码分为公开代码和私有代码。公开代码可以在项目外被使用,私有代码则只有项目内部的代码才可以访问。定义一个模块最基本的方式是使用 mod 关键字:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mod mod1 {
     pub mod mod2 {
          pub const MESSAGE: &str = "Hello World!"
          // ...
     }
     // ...
}

fn main() {
     println!(mod1::mod2::MESSAGE);
}

使用pub改变可见性

Rust 中模块内部的代码,结构体,函数等类型默认是私有的,但是可以通过 pub 关键字来改变它们的可见性。通过选择性的对外可见来隐藏模块内部的实现细节。

比较常用的三种 pub 写法:

  • pub:成员对模块可见
  • pub(self):成员对模块内的子模块可见
  • pub(crate):成员对整个 crate 可见

如果不使用 pub 声明,成员默认的可见性是私有的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mod mod1 {
    pub const MESSAGE: &str = "Hello World!";
    const NUMBER: u32 = 42;

    pub(self) fn mod1_pub_self_fn() {
        println!("{}", NUMBER);
    }

    pub(crate) enum CrateEnum {
        Item = 4,
    }

    pub mod mod2 {
        pub const MESSAGE: &str = "Hello World!";

        pub fn mod2_fn() {
            super::mod1_pub_self_fn();
        }
    }
}

fn main() {
    println!("{}", mod1::MESSAGE);
    println!("{}", mod1::mod2::MESSAGE);
    mod1::mod2::mod2_fn();
    println!("{}", mod1::CrateEnum::Item as u32);
}

结构体的可见性

结构体中的字段和方法默认是私有的,通过加上 pub 修饰语可使得结构体中的字段和方法可以在定义结构体的模块之外被访问。要注意,与结构体同一个模块的代码访问结构体中的字段和方法并不要求该字段是可见的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mod mod1 {
    pub struct Person {
        pub name: String,
        nickname: String,
    }

    impl Person {
        pub fn new(name: &str, nickname: &str) -> Self {
            Person {
                name: String::from(name),
                nickname: String::from(nickname),
            }
        }

        pub fn say_nick_name(&self) {
            println!("{}", self.nickname);
        }
    }
}

fn main() {
    let p = mod1::Person::new("jack", "baby");
    println!("{}", p.name);
    // println!("{}", p.nickname); // 不能访问 nickname
    p.say_nick_name();
}

使用use绑定模块成员

正常情况下当我们试图从模块内中访问其成员时,需要输入完整的路径,例如使用 std::fs::read 从磁盘上读取文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fn main() {
    let data = std::fs::read("src/main.rs").unwrap();
    println!("{}", String::from_utf8(data).unwrap());
}

可以使用 use 关键词将完整路径绑定到一个新的名称,这可以减少重复代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
use std::fs;

fn main() {
    let data = fs::read("src/main.rs").unwrap();
    println!("{}", String::from_utf8(data).unwrap());
}

可以使用 as 关键字将导入绑定到一个其他名称,它通常用在有多个不同模块都定义了相同名字的成员时使用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
use std::fs as stdfs;

fn main() {
    let data = stdfs::read("src/main.rs").unwrap();
    println!("{}", String::from_utf8(data).unwrap());
}

使用super与self简化模块路径

除了使用完整路径访问模块内的成员,还可以使用 super 与 self 关键字相对路径对模块进行访问:

  • super:上层模块
  • self:当前模块

当上层模块,当前模块或子模块中拥有相同名字的成员时,使用 super 与 self 可以消除访问时的歧义:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fn function() {
    println!("function");
}

pub mod mod1 {
    pub fn function() {
        super::function();
    }

    pub mod mod2 {
        fn function() {
            println!("mod1::mod2::function");
        }

        pub fn call() {
            self::function();
        }
    }
}

fn main() {
    mod1::function();
    mod1::mod2::call();
}

项目目录层次结构

将模块映射到文件

使用 mod <路径> 语法,将一个 rust 源码文件作为模块内引入:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
src
├── main.rs
└── mod1.rs

mod1.rs

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pub const MESSAGE: &str = "Hello World!";

main.rs

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mod mod1;

fn main() {
    println!("{}", mod1::MESSAGE);
}

将模块映射到文件夹

当一个文件夹中包含 mod.rs 文件时,该文件夹可以被作为一个模块:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
src
├── main.rs
└── mod1
    └── mod.rs

mod1/mod.rs

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pub const MESSAGE: &str = "Hello World!";

main.rs

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mod mod1;

fn main() {
    println!("{}", mod1::MESSAGE);
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
14.MySQL(二) 数据之表操作表内容操作Mysql 连接事务外键
数据之表操作 1.创建表 语法:CREATE TABLE table_name (column_name column_type); create table student( -> id INT NOT NULL AUTO_INCREMENT, -> name CHAR(32) NOT NULL, -> age INT NOT NULL, -> regiiter_date DATE, -> PRIMARY KEY(id) -> ); a
zhang_derek
2018/04/11
3.3K0
14.MySQL(二)
		数据之表操作表内容操作Mysql 连接事务外键
MYSQL库,表,记录的基本操作
  mysql – 用户权限相关数据   test – 用于用户测试数据   information_schema – MySQL本身架构相关数据
全栈程序员站长
2022/07/21
1.7K0
MYSQL库,表,记录的基本操作
MySQL单表&约束&事务
需求: 1 查询员工的总数 2 查看员工总薪水、最高薪水、最小薪水、薪水的平均值 3 查询薪水大于4000员工的个数 4 查询部门为’教学部’的所有员工的个数 5 查询部门为’市场部’所有员工的平均薪水
用户5513909
2023/04/25
1.3K0
MySQL单表&约束&事务
MySQL常用基础 - 小白必看
2、create database if not exists 数据库名 (判断数据库是否存在,不存在则创建)
EXI-小洲
2023/01/09
1.3K0
MySQL常用基础 - 小白必看
MySQL学习笔记2
DQL:查询语句 1. 排序查询 * 语法:order by 子句 * order by 排序字段1 排序方式1 , 排序字段2 排序方式2... * 排序方式: * ASC:升序,默认的。 * DESC:降序。 * 注意: * 如果有多个排序条件,则当前边的条件值一样时,才会判断第二条件。 2. 聚合函数:将一列数据作为一个整体,进行纵向的计算。 1. count:计算个数 1. 一般选
Eternity
2022/08/24
6850
【数据库_02】MySQL-约束
一、MySQL查询 1. 聚合函数 ① 统计 * 语法 count(需要统计的字段) * 注意 所有聚合函数都会自动跳过 null,解决方案 count(ifnull(字段,0));或count(*) * 示例 select count(*) from student; ② 最大值 * 语法 max(字段) * 示例 select max(math) from student; ③ 最小
用户8250147
2021/02/04
7470
MySQL常用语句
DDL操作数据库、表 1. 操作数据库:CRUD 创建(Create) 创建数据库:
一点博客
2019/07/24
7960
MySQL约束课堂笔记
张哥编程
2024/12/19
1610
MySQL的库表详细操作
  关于库的内容,咱们就说这些吧,哈哈,有点少是吧,不是咱们的重点,来看下面的表操作~~~
changxin7
2022/05/06
1.1K0
MySQL的库表详细操作
Mysql增删改查sql语句练习
Mysql增删改查sql语句练习 关于数据库的一些操作: 进入mysql 命令行: mysql -uroot –p 查看所有数据库: show databases; 创建数据库: create database wg charset utf8; 删除数据库: drop database wg; 选择数据库: use databases; 查看所有表: show tables; 查看创建数据库的语句:show create database databasename; 查看创建表的语句:show create table tablename; 查看表结构:desc tablename; 增: mysql> use wg; mysql> create table students( id int auto_increment primary key,name varchar(10) not null,sex varchar(12),address varchar(50),phone int not null unique); #自增长 auto_increment #非空 not null #默认值 default ‘xx’ #唯一 unique #指定字符集 charset #主键 primary key mysql> create table scores(id int auto_increment primary key,s_id int not null,grade float not null); 数据: mysql> insert into student (id,name,sex,phone) values(122,’wg’,’男’,’110’); mysql> insert into students values(111,’wg’,’121’,’dd’) ; 删: mysql> drop table tablename; mysql> truncate tablename; 快速删除表数据,自增长id从头在来,快速,从磁盘直接删除,不可恢复 mysql> delete from student; 删除整个表的数据,自增长继续 改: mysql> alter table oldtable rename newtable; 改表名 mysql> alter table scores modify s_id varchar(20);
全栈程序员站长
2022/07/25
2.2K0
Mysql增删改查sql语句练习
【MySQL】008-表的约束
说明链接:https://blog.csdn.net/u014743697/article/details/54136092
訾博ZiBo
2025/01/06
990
MySQL高级面试篇之索引详解大全
  索引是表的目录,在查找内容之前可以先在目录中查找索引位置,以此快速定位查询数据。对于索引,会保存在额外的文件中。
用户5224393
2019/08/13
6430
MySQL进阶之索引
索引是对数据库表中一个或多个列(例如,employee 表的姓名 (name) 列)的值进行排序的结构。如果想按特定职员的姓来查找他或她,则与在表中搜索所有的行相比,索引有助于更快地获取信息。
测试小兵
2019/11/19
4570
【MySQL】SQL语句查询、约束、备份与恢复
SELECT * FROM product ORDER BY price DESC;
陶然同学
2023/02/24
2K0
【MySQL】SQL语句查询、约束、备份与恢复
MySQL基础笔记
MySQL基础 一、数据库的基本概念 1.为什么要学数据库? 之前我们如果想将一些数据实现永久化存储,可以怎么做呢?没错。使用IO流的技术将数据保存到本地文件中 但是接下来我有这样一个需求:将下面的user.txt文件中的王五年龄修改为35 张三 23 男 李四 24 男 王五 25 女 赵六 26 女 周七 27 男 我们要如何实现呢? 可以采用字符缓冲流,将每一行数据读取出来,封装为User对象。将多个User对象保存到集合中 然后遍历集合,将王五对象的年龄修改为35,再重新将集合中的对象信息写
楠羽
2022/11/18
2.8K0
MySQL基础笔记
盘点MySQL慢查询的12个原因
日常开发中,我们经常会遇到数据库慢查询。那么导致数据慢查询都有哪些常见的原因呢?今天田螺哥就跟大家聊聊导致MySQL慢查询的12个常见原因,以及对应的解决方法。
捡田螺的小男孩
2023/02/24
1.5K0
盘点MySQL慢查询的12个原因
MySQL总结
2.alter table t1 modify name char(3); 修改类型
changxin7
2019/09/12
2K0
MySQL总结
My SQL常用操作汇总
写这篇随笔的目的是我发现了在上一篇关于My SQL的随笔中存在一些不严谨的代码问题,在这里再次简单的总结一下并加以改进,以代码为主。 # !每行命令必须以分号(;)结尾 先通过命令行进入数据库客户端 mysql -h服务端ip地址 -P(大写)服务端使用的端口,一般为3306 -p(小写) 回车之后输入密码,进入 显示所有数据库 show databases; 创建数据库并设置编码   - 数据库创建时可以设置字符集以及排序规则   - 字符集一般使用utf8的,排序规则一般使用忽略大
汪凡
2018/05/29
9550
MySQL[一]
1·什么是MySQL丶Oracle丶SQLite丶Access丶MS SQL Server等?
Wyc
2018/09/11
8830
12个MySQL慢查询的原因分析「建议收藏」
很多时候,我们的慢查询,都是因为没有加索引。如果没有加索引的话,会导致全表扫描的。因此,应考虑在 where 的条件列,建立索引,尽量避免全表扫描。
全栈程序员站长
2022/11/04
2K0
相关推荐
14.MySQL(二) 数据之表操作表内容操作Mysql 连接事务外键
更多 >
LV.2
晶扬电子AE工程师
目录
  • Rust中的模块化编程
    • Package
    • Crate
    • Module
  • 使用pub改变可见性
  • 结构体的可见性
  • 使用use绑定模块成员
  • 使用super与self简化模块路径
  • 项目目录层次结构
    • 将模块映射到文件
    • 将模块映射到文件夹
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档