《Rust权威指南》学习笔记(一)

基本介绍

1.Rust使用场景 :需要运行速度、需要内存安全、更好的利用多处理器。程序员无法在安全的Rust代码中执行任何非法的内存操作。相对于C#等带有垃圾回收机制的语言来讲,Rust遵循了零开销抽象(Zero-Cost Abstraction)规则,并为开发者保留了最大的底层控制能力。

2.Fuschia的Rust代码占了30%。

3.rustup update命令可以用来更新rust ;rustup self uninstall命令用来卸载rust;rustc  --version命令可以查看当前rust版本,对应输出格式为版本号、commit hash、commit日期;rustup doc命令可以直接查看本地的rust文档。

4.rust文件的后缀为.rs,命名规范为hello_world(单词之间用_隔开),用rustc name.rs编译rust文件,会生成与源文件同名且没有后缀的可执行文件。fn用来声明一个函数,以!结尾的是宏,否则是函数,每个语句以分号;结尾,每个rust程序都是从main函数开始执行的。

5.cargo是rust的构建系统和包管理工具,在rust中代码的包称为crate,可以用cargo new name命令来创建一个新项目,项目的名称就是name,会创建一个名为name的目录,下面有src目录存放源码文件,还会初始化一个git仓库,包括.gitignore,另外还有一个Cargo.toml文件(Tom’s Obvious,Minimal Language,这是cargo的配置文件)。用cargo build命令可以编译并创建可执行文件./target/debug/name(linux系统下生成的可执行文件的路径),第一次运行cargo build还会在顶层目录生成cargo.lock文件(该文件负责追踪项目依赖的精确版本,不需要手动修改该文件)。cargo run命令可以编译并运行文件,如果之前编译成功过,并且源码没有改变,那么就会直接运行二进制文件。cargo check命令用来检查代码确保它可以通过编译,但是不生成任何可执行文件。cargo build --release(一般正式发布用这个命令)会在编译时进行优化,可使代码运行的更快但是编译时间会更长,这个命令会在./target/release目录下生成可执行文件。

6.在Rust编程语言中,prelude是一个默认自动导入的模块,包含了一些常用的类型、函数和宏。它旨在提供一个基础的标准库功能集,使得开发者可以编写常见代码而不需要显式导入这些常用的组件。而对于其他模块则需要使用use进行导入。Rust中宏定义是以!结尾的,以此与函数区别开。fn用来声明一个函数,let用来声明一个常量(值不可变),let mut用来声明变量(mutable表示可变的)。

7.如果要使用库包crate,可以在Cargo.toml文件中的[dependencies]后面添加依赖的库及其版本号,第一次使用cargo build命令时会根据这些依赖在Cargo.lock文件中生成各个包的版本及其依赖信息,后面使用cargo run运行程序时这些版本信息不会改变,除非再次修改了Cargo.toml文件,另外也可以使用cargo update命令将Cargo.lock文件依赖的版本更新到最新的小版本(例如:0.3.1->0.3.最新小版本,不会升级到0.4以上版本),如果要更新到更高版本,还是需要手动修改Cargo.toml文件,然后再次编译运行程序时,Cargo.lock文件中的版本依赖信息将会被更新。

8.一个猜数游戏示例如下:

基本语法

1.声明变量使用let关键字(如:let x=5;),默认情况下变量是不可变的(Immutable),对于数字默认会被认为是i32类型的变量;声明变量时在变量前面加上mut,就可以使变量可变(如:let mut x=5;);Rust中变量不能在 全局作用域中声明,这样是因为Rust语言设计的主要原则之一是安全性,而全局变量容易引发数据竞争和不安全的并发操作;{}是占位符,相当于C语言中的%d。

2.常量(constant)在绑定值以后也是不可变的,但是它与不可变的变量有很多区别:不可以使用mut,常量永远都是不可变的;声明常量使用const关键字,它的类型必须被标注;常量可以在任何作用域内进行声明,包括全局作用域;常量只可以绑定到常量表达式,无法绑定到函数的调用结果或只能在运行时才能计算出的值;在程序运行期间,常量在其声明的作用域内一直有效;常量命名规范:常量使用全大写字母,每个单词之间用下划线分开,例如:const MAX_POINTS:u32 = 100_000。在编译期间,任何引用常量的代码会被替换为常量的计算结果值,常量没有内存或关联其他存储(因为他不是一个地方),可以把常量理解为某个特殊值的方便的名称。

3.可以使用相同的名字声明新的变量,新的变量就会 shadow(隐藏)之前声明的同名变量,在后续的代码中这个变量名代表的就是新的变量。shadow和把变量标记为mut是不一样的:如果不使用let关键字,那么重新给非mut的变量赋值会导致编译时错误;而使用let声明的同名新变量,如果没有重新声明为mut也是不可变的;使用let声明的同名新变量,它的类型可以与之前的不同,可变性也可以设与之前不同,如:let spaces=“   ”;let spaces=spaces.len();。

4.Rust 是静态编译语言,在编译时必须知道所有变量的类型,基于使用的值,编译器通常能够推断出它的具体类型,但如果可能的类型比较多 (例如把 String 转为整数的parse 方法),就必须添加类型的标注,否则编译会报错。Rust有以下四个主要的标量数据类型:1整数类型:无符号整数以u开头,如u32,有符号整数以i开头,如i32,isize和usize两个类型由运行程序的计算机架构决定(如果计算机是64位,则表示64位),整数类型默认是i32,0x、0o、0b、分别表示十六、八、二进制。Rust在整数溢出时不会panic报错;2浮点类型:有f32和f64两种浮点类型;3布尔类型:即bool,有true和false两个值;4字符类型:char类型被用来描述最基础的单个字符,但是一个字符占4个字节,字符类型的字面量使用单引号。

5.Rust复合类型一般有两种:1tuple:tuple可以将多个类型不同的多个值放在一个tuple里面,tuple的长度是固定的,一旦声明就无法改变,如:let tup:(i32,f64,u8)=(500,6.0,1);可以用模式匹配来获取Tuple中的元素值(let (x,y,z)=tup,然后xyz分别代表说上述tuple的第一二三个元素),也可以用点标记法来访问tuple中的元素,如tup.0、tup.1等;2数组:数组每个元素的类型必须相同,且数组的长度也是固定的,如:let a=[1,2,3,4],如果想让数据存放在栈上面而不是堆上面可以使用数组,数组的类型可以这样表示:let a:[i32;4]= [1,2,3,4];,如果数组中每个元素值相同也可以这样声明:let a=[3;5];(即[3,3,3,3,3]),数组元素通过索引访问,如a[0]表示第一个数组元素,如果数组越界rust会panic报错。

 6.函数声明需要使用fn关键字,函数名所有字母小写,单词之间用下划线_分开,在函数定义时必须声明每个参数的类型,函数由一系列语句组成(以;结尾),可选的由一个表示式结束,表达式会计算产生一个值,语句不提供返回值,所以不可以使用let将一个语句赋值给一个变量(如let x=(let y=6);),在->符号后边声明函数返回值的类型,但是不可以为返回值命名,返回值就是函数体中最后一个表达式的值,或者用return提前返回并指定一个返回值。注释可以使用//单行注释,也可使用/* */多行注释。如下图:

7.If表达式的条件必须是bool类型,如下图:

8.Rust提供三种循环:1loop循环:反复执行一段代码直到被中止,可以用break跳出loop循环;2while循环:每次执行循环体之前都判断一次条件;3for循环:更加简洁紧凑,可以针对集合中的每个元素来执行一些代码。如下图:

所有权和String

1.所有权是Rust最独特的特性,它让Rust无需GC(垃圾回收)就可以保证安全,在Rust中内存是通过一个所有权系统来管理的,其中包含一组编译器在编译时检查的规则。当程序运行时,所有权特性不会减慢程序的运行速度。

2.Stack按值的接收顺序来存储,按相反的顺序将它们移除(后进先出,LIFO),所有存储在Stack上的数据必须拥有已知的固定的大小,编译时大小未知的数据或运行时大小可能发生变化的数据必须存放在heap上。当把数据放入heap时,会请求一定数量的空间,操作系统在heap里找到一块足够大的空间,把它标记为在用,并返回一个指针,也就是这个空间的地址,这个过程叫做在heap上进行分配。把数据压到stack上要比在heap上分配快得多,因为操作系统不需要寻找用来存储新数据的空间,那个位置永远都在stack的顶端,在heap上分配空间需要做更多的工作,操作系统首先需要找到一个足够大的空间来存放数据,然后要做好记录方便下次分配。访问heap中的数据要比访问stack中的数据慢,因为需要通过指针才能找到heap中的数据,对于现代的处理器来说,由于缓存的缘故,如果指令在内存中跳转的次数越少,那么速度就越快,如果数据存放的距离比较近,那么处理器的处理速度就会更快一些(stack上),如果数据之间的距离比较远,那么处理速度就会慢一些(heap上)。

3.所有权规则:Rust中每个值都有一个变量,这个变量是该值的所有者,每个值同时只能有一个所有者,当该值的所有者超出其作用域时,该值会被删除。Rust中,对于某个值来说,当拥有它的变量走出作用范围时,内存会立即自动的交还给操作系统(Rust采用所有权系统来管理内存,当一个变量离开它的作用域时,Rust会自动调用该变量的drop函数(如果它实现了Drop trait))。

4.String类型:与字符串字面值不同(程序里手写的那些字符串值,它们是不可变的,字符串字面值在编译时就知道它的内容了,其文本内容直接被硬编码到最终的可执行文件中),String在heap上分配,能够存储在编译时未知数量的文本,操作系统必须在运行时来请求内存,当用完String之后,需要以某种方式将内存返回给操作系统。如果没有GC,就需要我们去识别内存何时不再使用并调用代码将它返回,如果忘了就会浪费内存,如果提前做了变量就会非法,如果做了两次也会造成BUG,必须是一次分配对应一次释放。可以使用from函数从字符串字面值创建出String类型,如:

一个String由三部分组成,一个指向存放字符串内容的内存的指针,一个长度,一个容量,如下图所示,左侧的内容存放在stack上,右侧的部分存放在heap上。

进行字符串复制时,为了防止二次释放的发生,Rust会让原本的字符串失效,它不会进行任何堆上内容的复制。如下图,灰色表示失效。

如果真想对heap上面的String数据进行深度拷贝,而不仅仅是stack上的数据,可以使用clone方法。

5.一个类型如果实现了Copy这样的trait(即接口),那么旧的变量在赋值后仍然是可用的,如果一个类型或者该类型的一部分实现了Drop trait,那么Rust不允许让它再实现Copy trait了,Copy trait可以用于像整数这种可以完全放在stack上的类型。一些拥有Copy trait的类型,如:任何简单标量的组合类型、所有整数类型(如u32)、bool、char、所有浮点类型、Tuple(如果其字段都是Copy的)。任何需要分配内存或者某种资源的都不是Copy的。

6.在语义上,将值传递给函数和把值赋值给变量是类似的,函数在返回值的过程中同样也发生所有权的转移,一个变量的所有权总是遵循相同的模式:当一个包含heap数据的变量离开作用域时,它的值就会被drop函数清理,除非数据的所有权移动到另一个变量上了。

7.想让函数使用某个值,而不获得其所有权可以使用引用,&就表示引用,例如参数的类型可以是&String而不是String。

通常把引用作为函数参数叫做借用,借用来的东西是不可以修改的。和变量一样,引用默认是不可变的,可以使用mut使其成为可变引用,对于不可变的变量是无法创建它的可变引用的,更不可能通过可变引用来修改不可变变量。

但在特定作用域中,对某一块数据只能有一个可变引用,这是为了防止数据竞争的发生。但可以通过创建新的作用域,来允许非同时的创建多个可变引用。

另外不可以同时存在一个可变引用和一个不可变引用,但同时存在多个不可变引用是可以的。

8.悬空引用:一个指针引用了内存中的某个地址,而这块内存可能已经释放并分配给其他人使用了,在Rust中编译器可保证引用永远都不是悬空引用。如下图会报错:

9.Rust的另外一种不持有所有权的数据类型,切片字符串的切片是指向字符串中一部分内容的引用,形式为[开始索引..结束索引],开始索引就是切片起始位置的索引值,但是结束索引指向切片终止位置的下一个索引。

字符串切片的索引范围必须发生在有效的UTF-8字符边界内,如果尝试从一个多字节的字符中创建字符串切片,程序就会报错并退出。字符串字面值实质上就是一个字符串切片,类型为&str,是一个指向二进制程序特定位置的切片,&str是不可变引用,所以字符串字面值也是不可变的。

结构体Struct

1.结构体常见定义和使用如下图:

结构体初始化时必须给每个成员都赋值,否则会报错,结构体成员可以使用点标记法来使用,如user1.email,结构体可声明为可变(mut)或者不可变的,一旦结构体的实例是可变的,那么实例中所有的字段都是可变的,不允许单独声明某个字段是否可变。当字段名与字段值对应的变量名相同时,就可以使用字段初始化的简写方式,如下图所示:

也可以使用struct的更新语法来基于某个struct创建新的struct,如下图:

可以定义类似tuple的struct,叫做tuple struct,tuple struct整体有一个名字,但是里面的元素没有名字,如:struct Color(i32,i32,i32);let black=Color(0,0,0);。没有任何字段的空结构体叫做Unit-Like Struct。

2.在Rust中,derive是一个属性(attribute),用于为一个结构体(struct)或枚举(enum)自动生成某些标准的trait实现。这些trait通常是一些通用功能的实现,手动编写可能比较繁琐,所以Rust提供了derive来自动生成。例如#[derive(Debug)]用于为一个结构体或枚举自动生成Debug trait的实现。这个trait允许使用{:?}以一种可读的格式打印出结构体或枚举的内容,通常用于调试。#[derive(...)]属性仅作用于其后面紧跟的结构体(struct)或枚举(enum)。

3.Struct中的方法:方法和函数类似,不同之处在于方法是在struct(或enum、trait对象)的上下文中定义的,方法的第一个参数是self(也可以写成&self或者&mut self),对应该方法被调用时的调用实例,方法需要在impl块中定义,每个struct可以拥有多个impl模块。对于方法的调用可以直接使用结构体实例名.方法名,在调用方法时Rust会根据情况自动添加&、&mut或*,以便object可以匹配方法的签名。

4.Struct中的关联函数:可以在Struct中定义不把self作为第一个参数的函数,这样的函数叫做关联函数,它相当于是与结构体关联的而不是结构体实例,可以通过::来调用关联函数,例如String::from(),

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

才气小波与第一性原理

才气小波与第一性原理 才气小波与第一性原理具身智能云藏山鹰类型物热力学第二定律的动力机械外骨骼诠释才气小波导引社会科学概论软凝聚态数学意气实体过程王阳明代数Wangyangmingian王阳明算符才气语料库命运社会科学概论意气实体过程业务分层框架示例 才气小波与第一性原理 …

JAVA:利用 Redis 实现每周热评的技术指南

1、简述 在现代应用中,尤其是社交媒体和内容平台,展示热门评论是常见的功能。我们可以通过 Redis 的高性能和丰富的数据结构,轻松实现每周热评功能。本文将详细介绍如何利用 Redis 实现每周热评,并列出完整的实现代码。 2、需求分…

Fabric环境部署-安装Go

安装go语言环境 国内镜像:Go下载 - Go语言中文网 - Golang中文社区 1.选择版本下载后解压:注意go1.11.linux-amd64.tar.gz换成你下的 sudo tar zxvf go1.21.linux-amd64.tar.gz -C /usr/local 2.. 创建Go目录 mkdir $HOME/go 3. 用vi打开~./bashrc&…

计算队列中的‘捣乱分子’对数:一种量化无序程度的方法

计算队列中的‘捣乱分子’对数:一种量化无序程度的方法 前言解题思路关键点实现代码时间复杂度分析前言 在日常生活中,我们经常会遇到需要排队的场景,比如买票、候车、就餐等。在理想的排队情况下,人们会按照某种顺序(如先到先服务)整齐地排成一列。然而,总有一些人不遵…

信号的产生、处理

一、信号的概念 信号是linux系统提供的一种,向指定进程发送特定事件的方式。收到信号的进程,要对信号做识别和处理。信号的产生是异步的,进程在工作过程中随时可能收到信号。 信号的种类分为以下这么多种(用指令kill -l查看&…

【机器学习】机器学习的基本分类-自监督学习-对比学习(Contrastive Learning)

对比学习是一种自监督学习方法,其目标是学习数据的表征(representation),使得在表征空间中,相似的样本距离更近,不相似的样本距离更远。通过设计对比损失函数(Contrastive Loss)&…

Flutter-插件 scroll-to-index 实现 listView 滚动到指定索引位置

scroll-to-index 简介 scroll_to_index 是一个 Flutter 插件,用于通过索引滚动到 ListView 中的某个特定项。这个库对复杂滚动需求(如动态高度的列表项)非常实用,因为它会自动计算需要滚动的目标位置。 使用 安装插件 flutte…

国内Ubuntu环境Docker部署CosyVoice

国内Ubuntu环境Docker部署CosyVoice 本文旨在记录在 国内 CosyVoice项目在 Ubuntu 环境下如何使用 dockermin-conda进行一键部署。 源项目地址: https://github.com/FunAudioLLM/CosyVoice 如果想要使用 dockerpython 进行部署,可以参考我另一篇博客中的…

计算机网络•自顶向下方法:网络层介绍、路由器的组成

网络层介绍 网络层服务:网络层为传输层提供主机到主机的通信服务 每一台主机和路由器都运行网络层协议 发送终端:将传输层报文段封装到网络层分组中,发送给边缘路由器路由器:将分组从输入链路转发到输出链路接收终端&#xff1…

信创云之天翼云:引领信创云时代的先锋力量

数据显示,2024年中国云服务市场规模已达到4242.5亿元,显示出各行业对信息技术软硬件的依赖程度不断加深。在国家政策的持续支持下,数字化转型为云服务行业带来了前所未有的发展机遇。预计到2025年,中国云服务市场规模将突破4795.4…

Elasticsearch:基础概念

一、什么是Elasticsearch Elasticsearch是基于 Apache Lucene 构建的分布式搜索和分析引擎、可扩展数据存储和矢量数据库。它针对生产规模工作负载的速度和相关性进行了优化。使用 Elasticsearch 可以近乎实时地搜索、索引、存储和分析各种形状和大小的数据。Elasticsearch 是…

智慧工地解决方案 1

建设背景与挑战 工地施工现场环境复杂,人员管理难度大,多工种交叉作业导致管理混乱,事故频发。传统管理方式难以实现科学、有效、集中式的管理,特别是在环境复杂、地点分散的情况下,监管困难,取证复杂。施…

若依中Feign调用的具体使用(若依微服务版自身已集成openfeign依赖,并在此基础上定义了自己的注解)

若依中Feign调用具体使用 注意:以下所有步骤实现的前提是需要在启动类上加入注解 EnableRyFeignClients 主要是为开启feign接口扫描 1.创建服务提供者(provider) 导入依赖(我在分析依赖时发现若依本身已经引入openfeign依赖,并在此基础上自定义了自己的EnableRyF…

基于Springboot +Vue 实验课程预约管理系统

基于Springboot Vue 实验课程预约管理系统 前言 在现代教育领域,实验课程预约管理系统扮演着至关重要的角色。随着教学资源的日益紧张和学生需求的多样化,传统的人工管理方式已难以满足高效、透明的课程安排需求。基于SpringBootVue的实验课程预约管理…

CSS2笔记

一、CSS基础 1.CSS简介 2.CSS的编写位置 2.1 行内样式 2.2 内部样式 2.3 外部样式 3.样式表的优先级 4.CSS语法规范 5.CSS代码风格 二、CSS选择器 1.CSS基本选择器 通配选择器元素选择器类选择器id选择器 1.1 通配选择器 1.2 元素选择器 1.3 类选择器 1.4 ID选择器 1.5 基…

【偏好对齐】通过ORM直接推导出PRM

论文地址:https://arxiv.org/pdf/2412.01981 相关博客 【自然语言处理】【大模型】 ΨPO:一个理解人类偏好学习的统一理论框架 【强化学习】PPO:近端策略优化算法 【偏好对齐】PRM应该奖励单个步骤的正确性吗? 【偏好对齐】通过OR…

springmvc--请求参数的绑定

目录 一、创建项目,pom文件 二、web.xml 三、spring-mvc.xml 四、index.jsp 五、实体类 Address类 User类 六、UserController类 七、请求参数解决中文乱码 八、配置tomcat,然后启动tomcat 1. 2. 3. 4. 九、接收Map类型 1.直接接收Map类型 &#x…

第五届电网系统与绿色能源国际学术会议(PGSGE 2025)

2025年第五届电网系统与绿色能源国际学术会议(PGSGE 2025) 定于2025年01月10-12日在吉隆坡召开。 第五届电网系统与绿色能源国际学术会议(PGSGE 2025) 基本信息 会议官网:www.pgsge.org【点击投稿/了解会议详情】 会议时间:202…

CSS——4. 行内样式和内部样式(即CSS引入方式)

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>方法1&#xff1a;行内样式</title></head><body><!--css引入方式&#xff1a;--><!--css的引入的第一种方法叫&#xff1a;行内样式将css代码写…

彩色图像分割—香蕉提取

实验任务 彩色图像分割—香蕉提取 利用香蕉和其它水果及其背景颜色在R,G,B分量上的差异进行识别,根据香 蕉和其它水果在R,G,B分量的二值化处理&#xff0c;获得特征提取的有效区域&#xff0c;然后提取 特征&#xff0c;达到提取香蕉的目的。附&#xff1a;统计各种水果及个数…