使用包、Crate 和模块管理项目(下)

1、使用 use 关键字将路径引入作用域

在之前的示例中我们引用模块中的函数或者结构体之类的,都是需要用到相对路径或者绝对路径去引用,然尔在这里,有一种方法可以简化这个过程。我们可以使用 use 关键字创建一个短路径,然后就可以在作用域中的任何地方使用这个更短的名字。

示例如下所示:

pub mod people {pub enum Sex {Man,Woman,}
}use crate::people::Sex;fn get_sex() {let man = Sex::Man;
}

在作用域中增加 use 和路径类似于在文件系统中创建软连接(符号连接,symbolic link)。通过在 crate 根增加 use crate::people::Sex,现在 Sex在作用域中就是有效的名称了,如同 Sex类型被定义于 crate 根一样。通过 use 引入作用域的路径也会检查私有性,同其它路径一样。

注意 use 只能创建 use 所在的特定作用域内的短路径。通过以下示例我们看一下。

pub mod people {pub enum Sex {Man,Woman,}
}
use crate::people::Sex;
mod ceshi {fn get_sex() {let man = Sex::Man;}
}

运行以下,看一下对应错误提示:

根据上图中所示:我们可以知道类型Sex没有被声明,所以use 声明的作用域和当前方法所在的作用域不同。如果在当前方法中进行引用,有2种方式:第一种就是通过super关键字去引用,use定义的值是在当前方法的父级种,第二种方式,就是use语句移动到当前模块种。

// 第一种方式
use crate::people::Sex;
mod ceshi {fn get_sex() {let man = super::Sex::Man;}
}
// 第二种方式
mod ceshi {use crate::people::Sex;fn get_sex() {let man = Sex::Man;}
}

1.1 创建惯用的 use 路径

在之前的示例当中,我们使用use的时候,直接引用到了具体的结构体类型定义,使用 use 引入结构体、枚举和其他项时,习惯是指定它们的完整路径。,示例如下所示:

pub mod root {pub mod people {pub enum Sex {Man,Woman,}}
}
use crate::root::people::Sex;
fn get_sex() {let man = Sex::Man;
}

如果是函数类型时,我们必须在调用函数时指定父模块,这样可以清晰地表明函数不是在本地定义的,同时使完整路径的重复度最小化。示例如下所示:

pub mod root {pub mod people {pub fn getPeo() {}}
}
use crate::root::people;
fn get_sex() {let man = people::getPeo;
}

这种习惯用法背后没有什么硬性要求:它只是一种惯例,人们已经习惯了以这种方式阅读和编写 Rust 代码。

这个习惯用法有一个例外,那就是我们想使用 use 语句将两个具有相同名称的项带入作用域,因为 Rust 不允许这样做。

use std::fmt;
use std::io;fn function1() -> fmt::Result {// --snip--Ok(())
}fn function2() -> io::Result<()> {// --snip--Ok(())
}

如你所见,使用父模块可以区分这两个 Result 类型。如果我们是指定 use std::fmt::Result 和 use std::io::Result,我们将在同一作用域拥有了两个 Result 类型,当我们使用 Result 时,Rust 则不知道我们要用的是哪个。这样就是我们指定到具体类型时,可能重名的几率太高,所以会引用到它的父级来区分就行。

1.2 使用 as 关键字提供新的名称

使用 use 将两个同名类型引入同一作用域这个问题还有另一个解决办法:在这个类型的路径后面,我们使用 as 指定一个新的本地名称或者别名。示例如下所示:

use std::fmt::Result;
use std::io::Result as ResultAli;fn function1() -> Result {// --snip--Ok(())
}fn function2() -> ResultAli<()> {// --snip--Ok(())
}

1.3 使用 pub use 重导出名称

使用 use 关键字,将某个名称导入当前作用域后,这个名称在此作用域中就可以使用了,但它对此作用域之外还是私有的。如果想让其他人调用我们的代码时,也能够正常使用这个名称,就好像它本来就在当前作用域一样,那我们可以将 pub 和 use 合起来使用。这种技术被称为 “重导出re-exporting)”:我们不仅将一个名称导入了当前作用域,还允许别人把它导入他们自己的作用域。

示例如下所示:

pub mod root {pub mod people {pub fn getPeo() {}}
}
pub use crate::root::people; // 重导出
fn get_sex() {let man = people::getPeo;
}

在这个修改之前,外部代码需要使用路径 my_project::root::people::getPeo()来调用 getPeo()函数。现在这个 pub use 从根模块重导出了 people模块,外部代码现在可以使用路径 restaurant::peopel::getPeo

1.4 使用外部包

在使用外部包时,在 Cargo.toml 中加入对应包名称以及对应的版本号,如下所示:

rand = "0.8.5"

在 Cargo.toml 中加入 rand 依赖告诉了 Cargo 要从 crates.io 下载 rand 和其依赖,并使其可在项目代码中使用。

接着,为了将 rand 定义引入项目包的作用域,我们加入一行 use 起始的包名,它以 rand 包名开头并列出了需要引入作用域的项。示例如下:

use rand::Rng;
fn main() {let secret_number = rand::thread_rng().gen_range(1..100);println!("res {}", secret_number)
}

cargo run运行一下会发现去下载对应的资源,然后再打印1到100之间的一个随机数如下所示:

1.5 嵌套路径来消除大量的 use 行

当需要引入很多定义于相同包或相同模块的项时,为每一项单独列出一行会占用源码很大的空间。示例如下所示:

use std::cmp::Ordering;
use std::io;

相反,我们可以使用嵌套路径将相同的项在一行中引入作用域。这么做需要指定路径的相同部分,接着是两个冒号,接着是大括号中的各自不同的路径部分,示例如下所示:

use std::{cmp::Ordering, io};

我们可以在路径的任何层级使用嵌套路径,这在组合两个共享子路径的 use 语句时非常有用。例如一下示例:

use std::io;
use std::io::Write;

两个路径的相同部分是 std::io,这正是第一个路径。为了在一行 use 语句中引入这两个路径,可以在嵌套路径中使用 self,示例如下所示:

use std::io::{self, Write};

1.6 通过 glob 运算符将所有的公有定义引入作用域

如果希望将一个路径下 所有 公有项引入作用域,可以指定路径后跟 *,glob 运算符:

use std::collections::*;

这个 use 语句将 std::collections 中定义的所有公有项引入当前作用域。使用 glob 运算符时请多加小心!Glob 会使得我们难以推导作用域中有什么名称和它们是在何处定义的。 

2、将模块拆分成多个文件 

前面的示例都是一个文件中定义多个模块。当模块变得更大时,你可能想要将它们的定义移动到单独的文件中,从而使代码更容易阅读。

例如在之前的 src/lib.rs 中的如下代码

pub mod garden {pub mod vegetables {#[derive(Debug)]pub struct Asparagus {pub color: String,pub number: i32,}}
}

然后对src/lib.rs文件种的内容进行改写,如下所示:

mod garden;use garden::vegetables::Asparagus;pub fn getAsparagus() {let res = Asparagus {color: String::from("red"),number: 12,};
}

首行声明了 mod garden;在src/garden.rs 文件种进行查找。内容如下所示:

pub mod vegetables;

 接着我们创建一个 src/garden 目录和一个包含 Asparagus结构体定义的 vegetables.rs文件:文件内容如下所示:

pub struct Asparagus {pub color: String,pub number: i32,
}

目录结构如下所示: 

my-project

├─ Cargo.lock

├─ Cargo.toml

├─ README.md

└─ src

   ├─ garden

   │  └─ vegetables.rs

   ├─ garden.rs

   ├─ lib.rs

   └─ main.rs

总结:

在引用模块的时候一般有两种方式:

第一种就是上面所示的src/garden/vegetables.rs

第二种方式方式就是src/garden.rs,vegetables模块写在当前文件中。

如果你对同一模块同时使用这两种路径风格,会得到一个编译错误。在同一项目中的不同模块混用不同的路径风格是允许的,不过这会使他人感到疑惑。

使用 mod.rs 这一文件名的风格的主要缺点是会导致项目中出现很多 mod.rs 文件,当你在编辑器中同时打开它们时会感到疑惑。

我们将各个模块的代码移动到独立文件了,同时模块树依旧相同。这样解耦性更强,更方便与后于模块的迁移和重构。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/221540.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

惯性导航基础知识学习---04惯导设备的使用

&#x1f308;武汉大学惯性导航课程合集是入门惯导的精品课程~ 作为导航路上的鼠鼠我&#xff0c;要开始学习惯性导航了~ 需要达到的要求是大致了解惯导的原理等~ 后期会陆续更新惯导相关的知识和笔记等~ &#x1f42c; 本blog为 武汉大学惯性导航课程 的记录~ 感谢团队提供的开…

mac电脑安装虚拟机教程

1、准备一台虚拟机&#xff0c;安装CentOS7 常用的虚拟化软件有两种&#xff1a; VirtualBoxVMware 这里我们使用VirtualBox来安装虚拟机&#xff0c;下载地址&#xff1a;Downloads – Oracle VM VirtualBox 001 点击安装 002 报错&#xff1a;he installer has detected an…

计网02-计算机网络参考模型

一、OSI七层参考模型 1、分层的思想 分层模型用于网络协议的设计方法&#xff0c;本质是将网络节点间复杂的通信问题分成若干简单的问题逐一解决&#xff0c;通过网络的层次去找问题&#xff0c;将复杂问题简单化。 2、OSI参考模型 由于早期计算机厂商使用的是私有的网络模…

map|动态规划|单调栈|LeetCode975:奇偶跳

作者推荐 【贪心算法】【中位贪心】.执行操作使频率分数最大 涉及知识点 单调栈 动态规划 map 题目 给定一个整数数组 A&#xff0c;你可以从某一起始索引出发&#xff0c;跳跃一定次数。在你跳跃的过程中&#xff0c;第 1、3、5… 次跳跃称为奇数跳跃&#xff0c;而第 2、…

【GoLang】哪些大公司正在使用Go语言

你见过哪些令你膛目结舌的代码技巧&#xff1f; 文章目录 你见过哪些令你膛目结舌的代码技巧&#xff1f;前言&#xff1a;哪些大公司正在使用Go语言谷歌&#xff08;Google&#xff09;&#xff1a;脸书&#xff08;Facebook&#xff09;&#xff1a;亚马逊&#xff08;Amazon…

LVS+keepalived小白都看得懂也不来看?

1 高可用集群 1.1 一个合格的集群应该具备的特性 1.负载均衡 LVS Nginx HAProxy F5 2.健康检查&#xff08;使得调度器检查节点状态是否可以正常运行&#xff0c;调度器&#xff08;负载均衡器&#xff09;也要做健康检查&#xff09;for调度器/节点服务器 keeplived hearb…

轻度听力损失的儿童需要早期干预吗?

一些宝宝在做听力筛查时总是不通过&#xff0c;进一步听力诊断发现宝宝有轻度的听力损失&#xff0c;刚知道这个消息时&#xff0c;家长可担心了&#xff0c;总想着宝宝是不是听不到啊&#xff1f;但是一段时间后&#xff0c;有些家长又会忽略宝宝的听力问题&#xff0c;因为部…

系列十四(面试)、谈谈你对StackOverflowError的理解?

一、StackOverflowError 1.1、概述 StackOverflowError是栈内存溢出的意思。栈中主要存储的是8种基本数据类型 引用类型 实例方法&#xff0c;栈的空间也是有限的&#xff0c;当存储进栈中的容量大于栈的最大容量时&#xff0c;就会报StackOverflowError的错误。 1.2、案例 …

Node.js使用Express框架写服务端接口时,如何将接口拆分到不同文件中

项目目录结构说明&#xff1a; node.js连接mysql数据库步骤可参考&#xff1a;Node.js 连接 MySQL | 菜鸟教程 1、拆分之前的写法&#xff0c;未区分模块&#xff0c;所有接口api都写在了入口文件app.js中&#xff1b; 需求&#xff1a;想要将接口api拆分成根据不同的业务模块…

大型语言模型:RoBERTa — 一种稳健优化的 BERT 方法

slavahead 一、介绍 BERT模型的出现BERT模型带来了NLP的重大进展。 BERT 的架构源自 Transformer&#xff0c;它在各种下游任务上取得了最先进的结果&#xff1a;语言建模、下一句预测、问答、NER标记等。 尽管 BERT 性能出色&#xff0c;研究人员仍在继续尝试其配置&#xff0…

旅游景区项目信息化建设运营方案:PPT47页,附下载

关键词&#xff1a;智慧景区解决方案&#xff0c;智慧景区建设&#xff0c;智慧景区开发与管理&#xff0c;智慧景区建设的意义&#xff0c;智慧景区管理 一、旅游景区项目信息化建设背景 1、旅游业发展迅速&#xff1a;随着旅游业的不断发展&#xff0c;游客对旅游体验的需求…

多级缓存:亿级流量的缓存方案

文章目录 一.多级缓存的引入二.JVM进程缓存三.Lua语法入门四.多级缓存1.OpenResty2.查询Tomcat3.Redis缓存预热4.查询Redis缓存5.Nginx本地缓存6.缓存同步 一.多级缓存的引入 传统缓存的问题 传统的缓存策略一般是请求到达Tomcat后&#xff0c;先查询Redis&#xff0c;如果未…

【LeetCode刷题】--245.最短单词距离III

245.最短单词距离III class Solution {public int shortestWordDistance(String[] wordsDict, String word1, String word2) {int len wordsDict.length;int ans len;if(word1.equals(word2)){int prev -1;for(int i 0;i<len;i){String word wordsDict[i];if(word.equa…

Xcode 恢复Discard Changes

当开发的时候&#xff0c;Discard All Changes后 文件的修改都被放弃了&#xff0c;怎么才可以撤销更改呢 Xcode和Git没有这个功能&#xff0c;Finder可以实现 首先我们先退出Xcode用TextEdit打开你想恢复的文件转到文件 > 还原到 > 浏览所有版本...选择你想恢复的版本即…

Notepad++:多行数据操作

1&#xff09;删除关键字之后&#xff08;或之前&#xff09;的所有字符 删除s之后&#xff08;包含s&#xff09;的所有内容&#xff1b;快捷键&#xff1a;s.*$ 替换成功 删除s之前&#xff08;包含s&#xff09;的所有内容&#xff1b;快捷键&#xff1a;^.*s 2&#xff09…

互式流程图|BPMN JointJS+ JavaScript 3.7.3 Crack

JointJS 是 JavaScript 图表库为卓越的 UI 提供支持 使用经过验证的库快速、自信地构建高级视觉和无代码/低代码应用程序。 赋能全球行业领导者 使用 JointJS 构建的图表 一个库&#xff0c;‍无限 UI 选项 直接在您的应用程序中享受交互式流程图、BPMN 和其他图表工作室。利用…

乐理基础-情绪与速度、具体的速度、BPM

首先音乐中的一拍并不是一个具体的时间&#xff08;详情看这两个 认识音符、什么是一拍&#xff09;&#xff0c;一拍并不是1图6&#xff1a;秒、2秒、3秒这样一个具体的时间&#xff0c;只能说在同样一份乐谱和同样一个速度下&#xff0c;全音符、二分音符、四分音符等等会依次…

aws配置以及下载 spaceNet6 数据集

一&#xff1a;注册亚马逊账号 注册的时候&#xff0c;唯一需要注意的是信用卡绑定&#xff0c;这个可以去淘宝买&#xff0c;搜索aws匿名卡。 注册完记得点击登录&#xff0c;记录一下自己的账户ID哦&#xff01; 二&#xff1a;登录自己的aws账号 2.1 首先创建一个用户 首…

QTNet:Query-based Temporal Fusion with Explicit Motion for 3D Object Detection

参考代码&#xff1a;QTNet 动机和出发点 自动驾驶中时序信息对感知性能具有较大影响&#xff0c;如在感知稳定性维度上。对于常见的时序融合多是在feature的维度上做&#xff0c;这个维度的融合主要分为如下两个方案&#xff1a; 1&#xff09;BEV-based方案&#xff1a;将之…

鸿蒙 - arkTs:渲染(循环 - ForEach,判断 - if)

ForEach循环渲染&#xff1a; 参数&#xff1a; 要循环遍历的数组&#xff0c;Array类型遍历的回调方法&#xff0c;Function类型为每一项生成唯一标识符的方法&#xff0c;有默认生成方法&#xff0c;非必传 使用示例&#xff1a; interface Item {name: String,price: N…