《Rust权威指南》学习笔记(二)
枚举enum
1.枚举的定义和使用如下图所示:
定义时还可以给枚举的成员指定数据类型,例如:enum IpAddr{V4(u8, u8, u8, u8),V6(String),}。枚举的变体都位于标识符的命名空间下,使用::进行分隔。
2.一个特殊的枚举Option(在预导入模块prelude中定义),它描述了某个值可能存在(某种类型)或者不存在的情况,Rust中没有Null。
3.控制流运算符match:允许一个值与一系列模式进行匹配,并执行匹配的模式对应的代码,模式可以是字面值、变量名、通配符等等。match表达式类似于一个函数,每个分支都会有一个返回值,并且整个match表达式的返回值类型必须一致。如下图:
Match匹配必须穷举所有的可能,否则会报错,可以用通配符_(这里可以用任何一个合法标识符来捕获剩下的匹配值)替代其余没有列出的值,_需要写在最后面,也可以使用任何合法的变量名捕获其他所有情况,后续可以在分支内部使用该变量进行进一步的处理。
4.if let的用法:处理只关心一种匹配而忽略其他匹配的情况,下图中v 恰好等于Some(3) 时,条件会成立,第一个分支就会被执行。if let还可以用于简化模式匹配,用于匹配并解构Option,、Result等枚举类型的某个特定变体,并在匹配成功时执行相应代码。
Rust代码组织
1.Package:是一个Rust项目的最外层单位,它由一个或多个crate组成(至少有一个)。它通常包含一个Cargo.toml文件,用于描述包的元数据、依赖项以及构建信息。每个package至少包含一个项目,这个项目可以是一个可执行项目(由main.rs文件定义)或者一个库项目(由lib.rs文件定义)。包和项目的关系是,一个package可以包含多个可执行项目(可放在src/bin目录下),但最多只能包含一个库项目。使用cargo new project创建一个新工程时,生成的就是一个Rust包(package)。想创建一个库包而不是可执行包,可以使用--lib选项。使用cargo new my_library --lib命令时,Cargo会在src/目录下创建一个lib.rs文件,而不是main.rs文件。这个lib.rs文件是库项目的入口文件,定义了库的公共API。
2.Crate:是Rust代码的编译单元,所有的Rust代码都是在crate的上下文中进行编译的。一个crate可以是一个库,也可以是一个可执行文件。每个crate都有一个根模块,根模块对应着crate的入口文件——对于库crate,入口文件是lib.rs,对于二进制crate,默认入口文件是main.rs(这个miain.rs编译生成的可执行文件名称与package名相同)。Crate定义了一个独立的命名空间,并且可以导入其他crate来使用它们的功能。由于main.rs是二进制crate的入口点,它的内容通常不会被库crate直接引用。因此,lib.rs中不能直接使用main.rs中定义的函数或结构体。相反,库crate应该定义功能,并将这些功能公开给其他模块或crate使用,而main.rs可以引用这些功能。
3.Module:是Rust中用于组织代码的机制,它允许将代码划分为多个部分,每个部分可以在其自己的命名空间中定义。模块帮助管理代码的可读性和可维护性,一个crate的根模块可以包含其他模块,而这些模块又可以嵌套定义子模块。Rust中的模块可以通过文件系统组织,例如,一个模块可以定义在与它同名的文件中,或者作为父模块文件中的嵌套模块定义,模块之间的关系通常通过use关键字和路径来引用。
4.Path:是Rust中用于引用项(例如函数、结构体、枚举、模块等)的方式,它定义了如何从一个命名空间访问另一个命名空间的内容。路径可以是绝对路径,从crate的根模块开始(可以使用crate名或者字面值“crate”);也可以是相对路径,从当前模块开始(使用self、super或当前模块的标识符,super用来访问父级模块路径中的内容,类似于文件系统中的..),路径的标识符之间用::隔开。路径使得你能够在模块层次结构中导航,访问不同模块和它们的内容。Rust的路径系统允许你清晰、简洁地访问代码片段,即使它们位于不同的模块或crate中。
5.私有边界:模块不仅可以组织代码,还可以定义私有边界,Rust中所有的条目(函数、方法、struct、enum、模块、常量等)默认都是私有的,父模块无法访问子模块中的私有条目,子模块可以使用所有祖先模块中的条目。可以使用pub来将这些条目声明为公有的,如下图,没有声明为公有的私有条目无法被访问:
6.use关键字:可以使用use关键字将路径(可以使用相对路径或者绝对路径)导作用域内(仍然遵循私有性规则),通常习惯将函数的父级模块引入作用域,以此来区分该函数是不是在其他模块引入的,而习惯将除函数外的其他元素如struct、enum等的整个完整路径引入作用域(如果有同名struct可以引用到父级以此来区分)。可以用as关键字来为引入的路径指定本地的别名,如:use std::fmt::Result as Re。
使用use将路径导入到作用域内后,该名称在此作用域中是私有的,可以在前面加上pub,则被导入的条目就可以被其他外部代码引入到他们的作用域中。如:pub use std::fmt::Result。
7.外部包的使用:需要现在Cargo.toml文件中添加依赖,然后用use将需要的特定条目引入到作用域内。标准库(std)也被当作外部包,不用在Cargo.toml文件中添加std,但需要用use将需要使用的std中的条目引入到当前作用域。当在Rust项目中使用cargo build命令编译程序时,Cargo(Rust的包管理器和构建系统)会将所有依赖的外部包下载并解压到target/debug/deps或target/release/deps文件夹中,具体位置取决于你是进行调试编译(debug)还是发布编译(release)。对于同一个包中的不同条目,可以使用嵌套路径的方式导入:路径相同的部分::{路径差异的部分}(路径差异部分用逗号分隔),如:use std::io::{cmp::Ordering,io};,如果两个use路径之一是另一个的子路径,可使用self,如:use std::io::{self,Write};。使用通配符*可以把路径中所有的公共条目都引入到作用域,如:use std::collections::*。
8.模块定义时,如果模块名后边是;,而不是代码块,Rust会从与模块同名的文件中加载内容,模块树的结构不会变化,如下图:
常见集合
1.Vector:由标准库提供,Vec<T>可以存储多个值,但只能存储相同类型的值,值在内存中连续存放。Vector初始化一般有两种方式,用new函数会初始化一个空的vector,还可以用宏定义vec!初始化,如下图所示:
向vector添加元素可以用push方法,例如v.push(1),添加的元素会被放在vector的末尾。当vector离开其作用域时,会像其他struct一样被清理掉,他里面所有的元素也会被清理掉。可以使用索引或者get方法来访问vector中的元素,get方法返回的是Option<T>枚举类型,所以当用get方法获取元素传入的索引越界时,返回的是None,而直接通过索引访问在越界时会引起panic。
所有权和借用规则在vector中同样适用,例如不能在同一作用域中同时拥有可变和不可变引用。可以用for循环来遍历vector中元素的值,如下图(println! 宏可以直接接受引用,所以不需要解引用i,就可以打印出其指向的值):
vector只能存储同一类型的数据,可以和enum配合使用来存储不同类型的值(将enum作为vector的元素),如下图:
2.字符串:字符串本质是Byte的集合,主要包括字符串字面值(&str)和String(由标准库提供,采用UTF-8编码)两种类型,Rust标准库还提供了其他字符串类型:OsString、OsStr、CString、CStr等。创建一个新的字符串可以使用new函数(如let mut s = String::new();),to_string()方法(可用于实现了Displaying trait的类型,包括字符串字面值)或者String::from()函数,如下图:
更新字符串的方式有:push_str()方法可以把一个字符串切片附加到String,如s.push_str(“abc”);表示将abc附加到s后面;push()方法可以把单个字符附加到String,如s.push(‘a’);;可以用+连接字符串,但只能把&str类型添加到String,即左侧操作数必须是String类型(左侧String的所有权会被消耗),右侧操作数必须是&str;format!可用来连接多个字符串(这种方式不会修改参数的所有权)。
String不支持索引的访问方式,可以将String看作是字节、标量或者字形,对于标量值可以用chars()方法来遍历,对于字节可以用bytes()方法来遍历。
可以使用[ ]和一个范围来创建字符串的切片,但如果切片跨越了字符边界就会报错(字符是以UTF-8编码的,有些字符占2-4个字节,切片的开始或结束位置不能在这样的2-4字节之间)。
3.HashMap<K,V>:以键值对的形式来存储数据,一个键对应一个值,Hash函数用来决定如何在内存中存放K和V。可以用new函数创建一个新的空HashMap(如let mut map = HashMap::new();),用insert方法向其中添加键值对(如map.insert("key1", "value1");)。在同一个HashMap中,所有的K必须是同一个类型,所有的V必须是同一个类型。还可以基于collect方法在元素类型为Tuple(要求Tuple有两个值,一个作为K,另一个作为V)的Vector上创建新的HahsMap,如下图:
在HashMap中,对于实现了Copy trait的类型(如i32),值会被复制到HashMap中,对于拥有所有权的值(如String),所有权会转移给HashMap,如果将值的引用插入到HashMap中,值的所有权不会转移,但在HashMap有效期间,被引用的值必须保持有效。可以用get方法传入参数K访问HashMap中的V,返回值为Option<T>枚举类型。可以用for遍历HashMap中的键值对,如下图:
更新HashMap有以下几种情况:1.K已经存在:可以选择替换现有的V、保留现有的V忽略新的V、合并现有的V和新的V;2.K不存在:添加一对KV。如果向HashMap插入一对KV,然后再插入同样的K不同的V则原来的V会被替换。可以先用entry方法检查指定的K是都存在(该方法返回enum Entry,代表值是否存在),然后使用Entry的or_insert()方法(若K存在,返回对应值的可变引用;若K不存在,该方法将参数作为K的新值插入HashMap,而后返回这个值的可变引用),如下图所示:
错误处理
1.Rust中将错误分为可恢复错误(例如文件未找到等,可再次尝试)和不可恢复错误(bug,例如索引访问越界),可恢复错误可返回Result<T,E>枚举类型,不可恢复错误和使用panic!宏来报错,这个宏的默认处理方式为展开(unwind)、清理调用栈,即从产生错误的地方开始,逆向遍历调用栈,逐层清理每一层函数调用所分配的资源。这个过程确保了所有已经获取的资源(例如内存、文件句柄、锁等)能够被正确地释放,避免资源泄漏。在展开过程中,Rust 会自动调用每个作用域中的析构函数(也称为Drop实现)释放资源或执行其他清理操作。然后退出程序。这样的默认操作比较费时,可以将其重新设置为panic!时直接中止调用栈,而不进行任何清理操作,内存清理交由操作系统去完成,具体设置可修改Cargon.toml文件,如下图:
panic!可能发生在我们自己写的程序中,也可能发生在我们程序所依赖的代码中,可以通过设置RUST_BACKTRACE环境变量回溯错误具体信息,如在运行时设置:cargo run RUST_BACKTRACE=1,但必须保证编译时没有加--realease选项。
2.Result枚举类型原始定义如下:
和Option一样,Result也是由prelude带入作用域,Result枚举类型可以作为函数返回值或match匹配结果,如下图:
3.unwrap()方法可用于从Option或Result类型中提取值。如果调用unwrap()时包含的值是Some或Ok,它将返回内部的值;如果是None或Err,它将触发恐慌(panic),程序会终止执行。expect()方法也用于从Option或Result类型中提取值,但与unwrap() 不同的是,它允许自定义panic时的错误消息。这样,当unwrap() 触发panic时,可以得到更明确的错误信息帮助调试。
4.错误处理的一种更加简洁和快捷的方式是使用?运算符,?运算符可以用于处理返回Result或Option类型的函数或表达式,如果Result是Ok,Ok中的值就是表达式的结果,然后继续执行程序;如果Result是Err,Err就是整个函数的返回值,相当于使用了return。如下图所示,从上到下代码逐渐简洁:
Trait std::convert::From上的from函数可以用于错误类型之间的转换,被?所应用的错误,会隐式地被from函数处理,当?调用from函数时,它所接收的错误类型会被转化为当前函数返回类型所定义的错误类型,只要每个错误类型实现了转换为所返回的错误类型的from函数。
相关文章:

《Rust权威指南》学习笔记(二)
枚举enum 1.枚举的定义和使用如下图所示: 定义时还可以给枚举的成员指定数据类型,例如:enum IpAddr{V4(u8, u8, u8, u8),V6(String),}。枚举的变体都位于标识符的命名空间下,使用::进行分隔。 2.一个特殊的枚举Option࿰…...

Redis内存碎片
什么是内存碎片? 你可以将内存碎片简单地理解为那些不可用的空闲内存。 举个例子:操作系统为你分配了 32 字节的连续内存空间,而你存储数据实际只需要使用 24 字节内存空间,那这多余出来的 8 字节内存空间如果后续没办法再被分配存储其他数…...

Express 加 sqlite3 写一个简单博客
例图: 搭建 命令: 前提已装好node.js 开始创建项目结构 npm init -y package.json:{"name": "ex01","version": "1.0.0","main": "index.js","scripts": {"test": &q…...
正则表达式进阶学习(一):环视、捕获分组与后向引用
一、环视(零宽断言) 理论部分 环视(零宽断言)是一种用于匹配位置而非字符的正则表达式技术。它的核心特点是:不消耗字符,只检查某个位置前后是否符合特定的条件。可以理解为,环视是在匹配前“…...

《Vue3 七》插槽 Slot
插槽可以让组件的使用者来决定组件中的某一块区域到底存放什么元素和内容。 使用插槽: 插槽的使用过程其实就是抽取共性、预留不同。将共同的元素、内容依然留在组件内进行封装;将不同的元素使用 slot 作为占位,让外部决定到底显示什么样的…...

【C++数据结构——线性表】顺序表的基本运算(头歌实践教学平台习题)【合集】
目录😋 任务描述 相关知识 一、线性表的基本概念 二、初始化线性表 三、销毁线性表 四、判定是否为空表 五、求线性表的长度 六、输出线性表 七、求线性表中某个数据元素值 八、按元素值查找 九、插入数据元素 十、删除数据元素 测试说明 通关代码 测…...

Linux C/C++编程-获得套接字地址、主机名称和主机信息
【图书推荐】《Linux C与C一线开发实践(第2版)》_linux c与c一线开发实践pdf-CSDN博客《Linux C与C一线开发实践(第2版)(Linux技术丛书)》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 (jd.com…...
USB kbtab linux 驱动代码
#include <linux/kernel.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/usb/input.h> #include <asm/unaligned.h> /* Pressure-threshold modules param code from */MODULE_AUTHOR(“xxx”); MODULE_DESCRIPTION(“…...

力扣 跳跃游戏
每次更新目标位置时,实际上是在做一个局部的最优选择,选择跳跃能够到达当前目标位置的最远位置。因为每次更新目标位置时,都是基于当前能跳跃到的最远位置,因此最终的结果是全局最优的。 题目 从前往后遍历,更新可以到…...
使用npm 插件[mmdc]将.mmd时序图转换为图片
使用npm 插件[mmdc]将.mmd时序图转换为图片 1. 安装 mmdc2. 转换为图片 可以使用 mmdc (Mermaid CLI)这个工具来将 .mmd 时序图(Mermaid语法描述的时序图)转换为图片,以下是使用步骤: 1. 安装 mmdc 确保…...

ffmpeg 常用命令
更详细请参考ffmpeg手册,下载ffmpegrelease版后在doc中就有,主页面。video filter 参考ffmpeg-filters.html -version -formats -demuxers -protocols -muxers -filters -devices —pix_fmts -codecs -sample_fmts -decoders -layouts -encoders -colors…...
从入门到实战:C 语言 strlen 函数通关指南
文章目录 一、strlen函数简介1. 函数构成2. 参数说明3. 使用示例 二、模拟实现strlen函数(从新手角度逐步升级改进)1. 基础版本(利用循环计数)2. 改进版本(利用指针相减)3. 递归版本(利用递归思…...

npm install --global windows-build-tools --save 失败
注意以下点 为啥下载windows-build-tools,是因为node-sass4.14.1 一直下载不成功,提示python2 没有安装,最终要安装这个,但是安装这个又失败,主要有以下几个要注意的 1、node 版本 14.21.3 不能太高 2、管理员运行 …...

十种基础排序算法(C语言实现,带源码)(有具体排序例子,适合学习理解)
学习了十种常见的排序方法,此文章针对所学的排序方法进行整理(通过C语言完成排序)。 参考内容: https://blog.csdn.net/mwj327720862/article/details/80498455 https://www.runoob.com/w3cnote/ten-sorting-algorithm.html 1. 冒…...

基于fMRI数据计算脑脊液(CSF)与全脑BOLD信号的时间耦合分析
一、前言 笔者之前的文章《基于Dpabi和spm12的脑脊液(csf)分割和提取笔记》,介绍了如何从普通的fMRI数据中提取CSF信号。首先是基础的预处理,包括时间层校正、头动校正,再加上0.01-0.1Hz的带通滤波。接着用SPM12分割出CSF区域,设置一个比较严格的0.9阈值,确保提取的真是…...

实现websocket心跳检测,断线重连机制
WebSocket基础 WebSocket概念 WebSocket是一种革命性的 全双工通信协议 ,构建在TCP之上,旨在简化客户端与服务器之间的数据交换过程。通过单次握手建立持久连接,WebSocket实现了真正的双向实时通信,显著提高了交互效率。这一特性…...

ComfyUI节点安装笔记
AI高速发展,版本更新相当快(11月25日才安装的版本v.0.3.4,27日版本就已经更新到v.0.3.5了),在遇到问题,找到问题原因所在的过程中,ComfyUI版本、python版本、节点对环境版本的依赖,本…...
深度学习,训练集准确率高,但验证集准确率一直不上升,很低的问题
在训练过程中,训练集的准确率稳步上升,但是验证集的准确率一直在40%左右徘徊,从网上搜索可能的原因有: 1、学习率太小,陷入局部最优。 2、数据量太小(4000多条数据,应该还可以吧) …...

【C语言程序设计——选择结构程序设计】求输入的日期是该年的第几天(头歌实践教学平台习题)【合集】
目录😋 任务描述 相关知识 1、switch 结构基本语法 2、示例代码及解释 3、使用注意事项 4、判断闰年的条件 编程要求 测试说明 通关代码 测试结果 任务描述 本关任务:编写程序实现:从键盘上输入一个年月日(以空格或回车…...
Lumos学习王佩丰Excel二十四讲系列完结
“Lumos学习王佩丰Excel二十四讲系列”是一套完整的Excel教程,涵盖了从基础到高级的各种知识和技能。是我亲自一个个码出来的教程哇!!! 一、课程概览 该教程共分为24讲,每一讲都围绕Excel的一个核心主题进行深入讲解…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...

51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...

IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...