当前位置: 首页 > news >正文

Rust核心:【所有权】相关知识点

rust在内存资源管理上采用了(先进优秀?算吗)但特立独行的设计思路:所有权。这是rust的核心,贯穿在整个rust语言的方方面面,并以此为基点来重新思考和重构软件开发体系。

涉及到的概念点:借用,引用,生命周期

借用(borrowing)

这里就要谈到这篇文章的主题,也是rust绕不开的主题:所有权。

所有权模型:Rust 的所有权模型允许值在内存中有唯一的所有者

一开始我以为:引用就是其他语言(如go)里常见的引用, 而借用是更在引用之上的一种抽象,是对我们【使用引用去达到目的】这种行为的抽象 。因为我看到在一些教程里直接将两者等同混用,但其实是不对的,
因为:Rust语言中的引用和其他语言中的引用不一样,其他语言里的引用是变量的别名,Rust语言中的引用是指向某个值的指针,而不是别名。在其他语言中,引用就相当于拿到了值的别名,跟原来的值是同一个东西,可以进行任何无差别访问。在Rust语言中的借用都是临时借用使用权,并不破坏单一所有权原则。

“借用” 是指通过引用来访问值而不获取所有权; Rust 使用 “借用” 这个术语来强调在借用期间,被借用的值的仍然归原所有者所有,并且原所有者在借用期间仍然保持可变性和原始值的所有权。
就好比我从你那里借了一本书,但我肯定不能随意在上面乱写乱画,因为书还是归你所有。所以Rust的借用默认是不可变的,如果想要修改借用的值,需要显示的声明使用可变借用&mut x(取得书主人的授权)。

通过借用而不是其他语言中的直接引用,可以确保在借用期间只有一个可变或不可变的访问者,避免了悬空指针和内存安全问题。

Rust里的借用没有开辟单独的表现方式,形式上仍然是其他语言里引用的样子:在rust里,以 变量前加“&”符来表示不可变借用,例如&x ,用&mut 表示可变借用,例如:&mut x。

从能力范围上来看: 借用包含了传统意义上的引用,但是能力范围又大于引用。注意这个图只是从能力范围上来看,可变借用和传统引用好像一样,本质还是不同的,即可变借用没有获取原始变量的所有权,就好比我租了你的房子,谈好条件可以让我装修,但房子还是你的,但在我装修房子后,你再给别的租客(别的借用)来看这个房子的时候, 这个房子会是装修好后的样子。
在这里插入图片描述
借用的限制
为了保证内存安全,Rust语言中的借用也有一些限制,比如:

  • 在同一作用域中,同一数据只能有一个可变借用,即多个可变借用不能同时存在(更准确是同一所有权型变量的多个可变借用作用域不能交叠)。
  • 在同一个作用域中,同一数据可以有多个不可变借用。
  • 在一个作用域中,可变借用与不可变借用不能同时存在 (更准确是可变借用与不可变借用的作用域不能交叠)
  • 所有借用的生命周期不能超出值的生命周期(防止悬垂指针,保证内存安全)。
  • 在有借用(包括可变借用和不可变借用)存在的情况下,不能通过原所有权型变量对值进行更新。当借用完成后(借用变量的作用域结束),物归原主,才又可以使用所有权型变量对值做更新操作了。
fn main(){let mut a = 10u32;let b = &a;a = 50;println!("{b}")
}
-----------------------
fn main(){let mut a = 10u32;let b = &mut a;a = 50;println!("{b}")
}
两个例子都不能通过编译

另外有个格外的要单独说明的点:可变引用的再赋值,会执行移动操作(而不是复制),赋值后,原来那个可变引用的变量就不能用了。可以看出:一个☝️所有权型变量的可变引用也具有所有权特征。

多级可变引用

对于多级可变引用,要利用可变引用去修改目标资源值的时候,需要做正确的多级解引用操作,比如两级引用就要对应两级接引用。而且这个引用过程中必须保证全是可变引用,才可以修改到目标资源的值。

对于多级引用的,打印语句可以为我们自动接引用到正确的层数,直至访问到目标资源值。这很符合人的意图和业务需求。

在这里有个有意思的对比:

go:
func main() {var a = 10var b = &afmt.Println(a)//output:10fmt.Println(b)//output:0x... (memory address )
}
rust:
fn main() {let a = 10u32;let b = &a;let c = &&&&&&&a;println!(a)//output:10println!(b)//output:10 println!(c)//output:10 
}

可以看到rust像gpt一样识别到了我们的人类意图,没有打印的引用的内存地址,而是打印了被引用对象的值。事实上,哪怕是像let c = &&&&&&&a这种对a的多级引用,rust也仍然正确获取了a的值。

触发所有权转移的行为

会触发所有权转移的行为有:赋值操作,函数入参,函数返回值,集合操作中的移动(如Vec、HashMap等),迭代器中的移动:

先来看一个列子

fn main() {let s = String::from("rust");let s1 = s; // s的所有权转移给了s1, s不再有效// println!("{}", s); // 此处会报错,因为s已经不再有效println!("{}", s1);// s1释放
}

上面的例子中,当把s赋值给s1时,s的所有权转移到了s1,s不再有效,也就是Move语义,以确保字符串rust在同一时刻只能有一个所有者。当s1离开作用域时,s1的所有权释放,字符串rust也随之释放。
再来看下边一个:

fn main(){let  a = 10u32;let b = a;println!("{a}");// 此处不会报错,此时a和b都是有效的// a 释放println!("{b}");// b 释放
}

为什么字符串的复制会报错 而整数类型不会报错呢?

这是因为Rust对简单数据类型做了处理。假如整型、浮点型、布尔型等,这都需要转移所有权,那这程序编写起来也太复杂了吧。所以Rust语言对于这些简单数据类型,采用了Copy trait来实现,这样就是复制,而不是转移所有权。在上边的例子中因为a是简单数据类型,采用了Copy trait,所以a和b都是有效的。
实现了Copy trait的类型,在赋值或者传参时,值会自动按位拷贝;而对于没有实现Copy trait的类型,会采用Move转移所有权的方式来传递数据。

实现了Copy trait的类型:

  • 原生类型:整型(i8,u8,i16,u16,i32,u32,i64,u64,i128,u128,isize,usize)、浮点型(f32,f64)、布尔型、字符型(char)、单元类型()、Never Type(!)。
  • 不可变引用(&T)
  • 函数指针
  • 裸指针(*const T, *mut T)
  • 数组[T;N]、元组(T1, T2, …, Tn)、Option类型(需要注意的是:只有当它们的元素类型都实现了Copy trait时,它们才实现了Copy trait)。

对于复合类型,比如枚举体和结构体,Rust语言默认是不实现Copy trait的,但是如果这些类型的所有成员都实现了Copy trait,那么你可以手动添加#[derive(Copy, Clone)]来实现Copy trait。如果内部结构包含Move语义的类型,那么就无法实现Copy trait。

相关文章:

Rust核心:【所有权】相关知识点

rust在内存资源管理上采用了(先进优秀?算吗)但特立独行的设计思路:所有权。这是rust的核心,贯穿在整个rust语言的方方面面,并以此为基点来重新思考和重构软件开发体系。 涉及到的概念点:借用&am…...

单片机05__串口USART通信__按键控制向上位机传输字符串

串口USART通信 通用UART介绍 1.通信的概念 计算机与外界进行信息交换的过程称之为通信。 在通信的过程中,通信双方都需要遵守的规则称之为通信协议。 硬件协议:将数据以什么样的方式传输过去 软件协议:将数据以什么样的顺序传输过去 2.常用…...

实习日志30

概要 高拍仪硬件通信原理,WebSocket源码解析(JavaScript) WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。 WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据…...

【MySQL】探索表结构、数据类型和基本操作

表、记录、字段 数据库的E-R(entity-relationship,实体-关系)模型中有三个主要概念: 实体集 、 属性 、 关系集 。 一个实体集对应于数据库中的一个表,一个实体则对应于数据库表 中的一行,也称为一条记录。…...

解决采集时使用selenium被屏蔽的办法

解决采集时使用selenium被屏蔽的办法 实用seleniumbase uc模式 from seleniumbase import Driver driver Driver(ucTrue) # 使用UC模式UC模式是基于undetected-chromedriver 但做了一些优化更新,使用起来更方便 官方例子: from seleniumbase import …...

stream流-> 判定 + 过滤 + 收集

List<HotArticleVo> hotArticleVos hotArticleVoList .stream() .filter(x -> x.getChannelId().equals(wmChannel.getId())).collect(Collectors.toList()); 使用Java 8中的Stream API对一个名为hotArticleVoList的列表进行过滤操作&#xff0c;筛选出符合指定条件…...

人工智能在测绘行业的应用与挑战

目录 一、背景 二、AI在测绘行业的应用方向 1. 自动化特征提取 2. 数据处理与分析 3. 无人机测绘 4. 智能导航与路径规划 5. 三维建模与可视化 6. 地理信息系统&#xff08;GIS&#xff09;智能化 三、发展前景 1. 技术融合 2. 精准测绘 3. 智慧城市建设 4. 可…...

四、分类算法 - 随机森林

目录 1、集成学习方法 2、随机森林 3、随机森林原理 4、API 5、总结 sklearn转换器和估算器KNN算法模型选择和调优朴素贝叶斯算法决策树随机森林 1、集成学习方法 2、随机森林 3、随机森林原理 4、API 5、总结...

pytorch -- DataLoader

定义 提供了给定数据集的迭代器 torch.utils.data.DataLoader(dataset, batch_size1, 每次拿多少数据 shuffleNone, 是否打乱 samplerNone, batch_samplerNone, num_workers0, 多进程&#xff08;加载数据时采用&#xff09;默认是0,使用主进程加载数据 collate_fnNone, p…...

【MySQL面试复习】索引创建的原则有哪些?

系列文章目录 在MySQL中&#xff0c;如何定位慢查询&#xff1f; 发现了某个SQL语句执行很慢&#xff0c;如何进行分析&#xff1f; 了解过索引吗&#xff1f;(索引的底层原理)/B 树和B树的区别是什么&#xff1f; 什么是聚簇索引&#xff08;聚集索引&#xff09;和非聚簇索引…...

四种主流的prompt框架

省流版&#xff1a; 文章介绍了在使用GPT时的四种prompt框架&#xff0c;有利于使用者打磨提问风格&#xff0c;与GPT进行更好的交互以提高生产力&#xff0c;能帮助大家有效提高工作效率~ 创作不易&#xff0c;如果对你有帮助的话&#xff0c;还请三连支持~ 想要使用Prompt…...

Educational Codeforces Round 160 (Rated for Div. 2) E. Matrix Problem(费用流)

原题链接&#xff1a;E. Matrix Problem 题目大意&#xff1a; 给出一个 n n n 行 m m m 列的 0 / 1 0/1 0/1 矩阵&#xff0c;再给出一些限制条件&#xff1a;一个长为 n n n 的数组 a a a&#xff0c;和一个长为 m m m 的数组 b b b 。 其中 a i a_{i} ai​ 表示第 …...

基于SpringBoot的气象数据监测分析大屏

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…...

关于硅的制造芯片的过程

芯片是如何制作的&#xff1f; 先将硅融化制成硅晶片&#xff0c;再用光刻机印压电路。 bilibili芯片制作视频 硅晶片作为现代芯片的主要元件&#xff0c;广泛用于集成电路。 首先将多晶硅放入特制的密封炉&#xff0c;排除其中空气后加热到1420摄氏度&#xff0c;将融化的硅放…...

【深度学习笔记】3_10 多层感知机的PyTorch实现

注&#xff1a;本文为《动手学深度学习》开源内容&#xff0c;仅为个人学习记录&#xff0c;无抄袭搬运意图 3.10 多层感知机的简洁实现 下面我们使用PyTorch来实现上一节中的多层感知机。首先导入所需的包或模块。 import torch from torch import nn from torch.nn import …...

输入法在 Android13上候选词 候选区域 不显示的问题

背景 自研的输入法发现在 Android13 平台上不显示候选区域&#xff0c;在之前平台上以及需求是输入英文时不显示&#xff0c;中文需要显示。 最终解决办法&#xff1a;setExtractViewShown(false) Override public View onCreateCandidatesView() {...setExtractViewShown(f…...

Java 面向对象进阶 18 JDK8、9开始新增的方法;接口的应用;适配器设计模式;内部类(黑马)

一、JDK8开始新增的方法 默认方法不是抽象方法&#xff0c;所以不强制被重写&#xff1a; 但是如果被重写&#xff0c;就要去掉default关键字&#xff1a; public可以省略&#xff0c;但是default不可以省略&#xff1a; public是灰色的&#xff0c;代表可以省略 但是default是…...

数据结构-二分搜索树(Binary Search Tree)

一,简单了解二分搜索树 树结构: 问题:为什么要创造这种数据结构 1,树结构本身是一种天然的组织结构,就好像我们的文件夹一样,一层一层的. 2,树结构可以更高效的处理问题 二,二分搜索树的基础 1、二叉树 2,二叉树的重要特性 满二叉树 总结: 1. 叶子结点出现在二叉树的最…...

YOLO如何训练自己的模型

目录 步骤 一、打标签 二、数据集 三、跑train代码出模型 四、跑detect代码出结果 五、详细操作 步骤 一、打标签 &#xff08;1&#xff09;在终端 pip install labelimg &#xff08;2&#xff09;在终端输入labelimg打开 如何打标签&#xff1a; 推荐文章&#xf…...

05 EXTI外部中断

一、中断系统 中断系统&#xff1a;管理和执行中断的逻辑结构。中断&#xff1a;在主程序运行过程中&#xff0c;出现了特定的中断触发条件——中断源&#xff0c;使得CPU暂停当前正在运行的程序&#xff0c;转而去处理中断程序&#xff0c;处理完成后又返回原来被暂停的位置继…...

2024.2.23

1.1.1 信号默认、捕获、忽略处理(普通信号) #include <myhead.h> void handler(int signo) {if(signoSIGINT){printf("用户键入 ctrlc\n");} } int main(int argc, const char *argv[]) {//忽略信号if(signal(SIGINT,SIG_IGN)SIG_ERR){perror("signal er…...

PHP实现分离金额和其他内容便于统计计算

得到的结果可以粘贴到excel计算 <?php if($_GET["x"] "cha"){ $tips isset($_POST[tips]) ? $_POST[tips] : ; $pattern /(\d\.\d|\d)/; $result preg_replace($pattern, "\t\${1}\t", $tips); echo "<h2><strong>数…...

基础数据结构和算法《》

递归 1.递归应该一种比较常见的实现一些特殊代码逻辑时需要做的&#xff0c;但常常也是最绕的一种方式&#xff0c;在解释递归 之前&#xff0c;我们用循环和递归来做个比较1.1.如果你打开一扇门后&#xff0c;同样发现前方也有一扇们&#xff0c;紧接着你又打开下一扇门...直…...

[设计模式Java实现附plantuml源码~行为型]对象间的联动~观察者模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…...

vue3+js 实现记住密码功能

常见的几种实现方式 1 基于spring security 的remember me 功能 ​​​​​​​ localStorage 除非主动清除localStorage 里的信息 &#xff0c;不然永远存在&#xff0c;关闭浏览器之后下次启动仍然存在 存放数据大小一般为5M 不与服务器进行交互通信 cookies 可以…...

基于单片机的太阳能电池板自动跟踪系统的研究

摘要 伴随着人类社会的发展,人口基数越来越大,电量消耗巨大,传统发电原 料污染环境的同时,可用量日益减少,给人类未来生产生活带来了一定的威胁, 因而解决日益剧增的用电量,寻求一种新能源显得极其重要。论文正是基于此 背景下,针对当前太阳能电池板采光率低、自动化水…...

React 模态框的设计(二)

自定义组件是每个前端开发者必备的技能。我们在使用现有框架时难免有一些超乎框架以处的特别的需求&#xff0c;比如关于弹窗&#xff0c;每个应用都会用到&#xff0c;但是有时我们使用的框架中提供的弹窗功能也是功能有限&#xff0c;无法满足我们的应用需求&#xff0c;今天…...

操作符详解3

✨✨ 欢迎大家来到莉莉的博文✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 前面我们已经讲过算术操作符、赋值操作符、逻辑操作符、条件操作符和部分的单目操作 符&#xff0c;今天继续介绍一部分。 目录 1.操作符的分类 2…...

【C语言基础】:操作符详解(一)

文章目录 操作符详解1. 操作符的分类2. 二进制和进制转换2.1 什么是二进制、八进制、十进制、十六进制2.1.1 二进制和进制转换2.1.2 二进制转十进制2.2.3 二进制转八进制2.2.4 二进制转十六进制 3. 源码、反码、补码4. 移位操作符4.1 左移操作符4.2 右移操作符 5. 位操作符&…...

通俗易懂分析:Vite和Webpack的区别

1、对项目构建的理解 先从浏览器出发&#xff0c; 浏览器是由浏览器内核和JS引擎组成&#xff1b;浏览器内核编译解析html代码和css代码&#xff0c;js引擎编译解析JavaScript代码&#xff1b;所以从本质上&#xff0c;浏览器只能识别运行JavaScript、CSS、HTML代码。 而我们在…...