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

Rust 中的引用与借用

目录

1、引用与借用

 1.1 可变引用

1.2 悬垂引用

1.3 引用的规则

2、slice 类型

 2.1 字符串字面量其实就是一个slice

2.2 总结


1、引用与借用

在之前我们将String 类型的值返回给调用函数,这样会导致这个String会被移动到函数中,这样在原来的作用域不可访问了,但是我们功能一个String值得引用,这样就不会导致这个String类型的值被移动,而传递的只是一个引用。引用更像一个指针,因为是一个地址,我们就可以基于这个地址找到改地址上存储的数据。 与指针不同,引用确保指向某个特定类型的有效值。

下面是一个引用传递的示例:

fn main() {let str = String::from("hello world!");let len = _length(&str);println!("str is value: {}", str);println!("str length is: {}", len)
} 
fn _length(s: &String) ->usize {s.len()
}

 运行结果所示所示:

根据以上代码可以看出_length方法中传递的参数为&str,所以这里传递的是str值的引用,用&符号代表引用

以下是一张对应的示意图:

根据上图也能看出s是s1的引用,引用的是s1在堆中对应类型的值。

注意:与使用 & 引用相反的操作是 解引用dereferencing),它使用解引用运算符,*

变量 s 有效的作用域与函数参数的作用域一样,不过当 s 停止使用时并不丢弃引用指向的数据,因为 s 并没有所有权。当函数使用引用而不是实际值作为参数,无需返回值来交还所有权,因为就不曾拥有所有权。

我们将创建一个引用的行为称为 借用borrowing),因为我们并没有拥有它的所有权,只是暂时借用以下。

我们可以尝试修改一下引用,把引用值改了,看下是否可以,这就类似于我借了别人的东西,然后把东西换了个样子,看看是不是可以呢?

fn main() {let str = String::from("hello world!");let len = _length(&str);println!("str is value: {}", str);
} 
fn _length(s: &String) {s.push_str("我把你给改了..........");
}

运行一下,看下结果:

根据提示可以s是一个引用,因此它引用的数据不能作为可变数据借用。

 1.1 可变引用

允许我们修改一个借用的值,这就是 可变引用,把上面的示例改一下,如下所示:

fn main() {let mut str = String::from("hello world!");_length(&mut str);println!("str is value: {}", str);
} 
fn _length(s: &mut String) {s.push_str("我把你给改了..........");
}

运行代码,再看一下结果:

 首先定义str必须时可变的,在方法中传递参数,也要指定引用为可变引用,因为引用指向的是被引用的地址,所以就会改变原有的值。

注意:可变引用有一个很大的限制:如果你有一个对该变量的可变引用,你就不能再创建对该变量的引用。

 看以下示例:

fn main() {let mut str = String::from("hello world!");let a = &mut str;let b = &mut str;println!("a {}, b{}", a, b)
} 

 根据错误提示,可以知道同一时间不能多次借用str作为可变变量。Rust这样限制是因为可以在编译时就避免数据竞争。数据竞争data race)类似于竞态条件,它可由这三个行为造成:

  • 两个或更多指针同时访问同一数据。
  • 至少有一个指针被用来写入数据。
  • 没有同步数据访问的机制。

再看下以下示例:

fn main() {let mut str = String::from("hello world!");let c = &mut str;let b = &str;println!("b{} {}", b, c)
} 

 也会报错,借用和可变借用不能同时被使用。

 再看下一个示例:

fn main() {let mut str = String::from("hello world!");let c = &mut str;println!("{}", c);let b = &str;println!("{}", b)
} 

 可以看到这次是可以打印处结果的,在第一次打印的时候,变量的作用域也就结束了,因而在下次进行赋值时可以的。

1.2 悬垂引用

在具有指针的语言中,很容易通过释放内存时保留指向它的指针而错误地生成一个 悬垂指针dangling pointer),所谓悬垂指针是其指向的内存可能已经被分配给其它持有者。相比之下,在 Rust 中编译器确保引用永远也不会变成悬垂状态:当你拥有一些数据的引用,编译器确保数据不会在其引用之前离开作用域。

下面时一个悬垂应用的示例:

fn main() {dp();
} 
fn dp() -> &String {    // 返回字符串的引用let str = String::from("hello world!");   // 创建一个字符串&str      // 返回字符串的引用
}  // str 的作用域结束
// 方法返回的时字符串的引用,而字符串离开作用与,被释放,然在此返回该字符串的引用,
// 就会导致返回的结果不是预期的结果,在Rust中是不让这样操作的。

 直接运行,会报如下错误:

根据报错可知,此函数的返回类型包含借用值,但没有可供借用的值,在返回类型引用处,提示: 错误的声明周期修饰符。

我们改以下返回字符串本身,看一下结果怎么样?

fn main() {println!("value is {}", dp())
} 
fn dp() -> String {    let str = String::from("hello world!");   return str
}  

运行一下看看:

发现对应的值给打印出来,所有权交出去了,所以,可打印出对应的值。

1.3 引用的规则

根据之前的结果,我们可以总结出以下两点:

  • 在任意给定时间,要么 只能有一个可变引用,要么 只能有多个不可变引用。
  • 引用必须总是有效的。

2、slice 类型

 slice 允许你引用集合中一段连续的元素序列,而不用引用整个集合。slice 是一类引用,所以它没有所有权。

以下有个slice示例:

fn main() {let s = String::from("hello world");let hello = &s[0..5];let world = &s[6..11];println!("{}---{}", hello, world)  
} 

运行以下,看下结果如何: 

根据以上结果,可以知道hello变量从字符串(hello world)中进行截取的,开始的位置为0,长度为5,所以打印的结果为hello,而world变量是从开始索引6开始,11结束,11-5=6,那么它的长度也是5,所以打印的结果为world.

Slice 的主要结果包括2部分:

  • 第一部分,是指针,指向数据开始的位置
  • 第二部分,是长度,就是元素结束减去开始位置的值

以下是一个示意图,能够更加清楚知道slice与字符串的关系:

其他写法,例如取前5个字符:

fn main() {let s = String::from("hello world");let hello = &s[0..5];let hello1 = &s[..5];  // hello 和 hello1 是等价的println!("{}---{}", hello, hello1)  
} 

例如取最后5个字符:

fn main() {let s = String::from("hello world");let world = &s[6..];let world1 = &s[6..];println!("{}---{}", world, world1)  
} 

取整个长度的切片:

fn main() {let s = String::from("hello world");let world = &s[..];let world1 = &s[..];println!("{}---{}", world, world1)  
} 

注意:字符串 slice range 的索引必须位于有效的字符边界内,如果尝试从超过边界访问超出索引范围将导致panic错误。

 2.1 字符串字面量其实就是一个slice

一个示例如下所示:

这里 s1 的类型是 &str:world 的类型也是&str,所以s1它是一个指向二进制程序特定位置的 slice。这也就是为什么字符串字面值是不可变的;&str 是一个不可变引用。

2.2 总结

所有权、借用和 slice 这些概念让 Rust 程序在编译时确保内存安全。Rust 语言提供了跟其他系统编程语言相同的方式来控制你使用的内存,但拥有数据所有者在离开作用域后自动清除其数据的功能意味着你无须额外编写和调试相关的控制代码。

相关文章:

Rust 中的引用与借用

目录 1、引用与借用 1.1 可变引用 1.2 悬垂引用 1.3 引用的规则 2、slice 类型 2.1 字符串字面量其实就是一个slice 2.2 总结 1、引用与借用 在之前我们将String 类型的值返回给调用函数,这样会导致这个String会被移动到函数中,这样在原来的作用域…...

Azure 机器学习:在 Azure 机器学习中使用 Azure OpenAI 模型

目录 一、环境准备二、Azure 机器学习中的 OpenAI 模型是什么?三、在机器学习中访问 Azure OpenAI 模型连接到 Azure OpenAI部署 Azure OpenAI 模型 四、使用自己的训练数据微调 Azure OpenAI 模型使用工作室微调微调设置训练数据自定义微调参数部署微调的模型 使用…...

XML Web 服务 Eclipse实现中的sun-jaxws.xml文件

说明 在sun-jaxws.xml文件,可以配置endpoint、handler-chain等内容。在这个文件中配置的内容会覆盖在Java代码中使用注解属性配置的的内容。 这个文件根据自己的项目内容修改完成以后,作为web应用的一部分部署到web容器中(放到web应用的WEB…...

16.1 二次根式 教学设计及课堂检测设计

课堂检测如下:...

Android数据流的狂欢:Channel与Flow

在 Android 应用程序的开发中,处理异步数据流是一个常见的需求。为了更好地应对这些需求,Kotlin 协程引入了 Channel 和 Flow,它们提供了强大的工具来处理数据流,实现生产者-消费者模式,以及构建响应式应用程序。 本文…...

Java 单元测试最佳实践:如何充分利用测试自动化

单元测试是众所周知的做法,但还有很大的改进空间!在这篇文章中,我们讨论最有效的单元测试最佳实践,包括在此过程中最大化自动化工具的方法。我们还将讨论代码覆盖率、模拟依赖关系和整体测试策略。 什么是单元测试? 单…...

windows系统用于 SDN 的软件负载均衡器 (SLB)

适用于:Azure Stack HCI 版本 22H2 和 21H2;Windows Server 2022、Windows Server 2019、Windows Server 2016 软件负载均衡器包括哪些内容? 软件负载均衡器提供以下功能: 适用于北/南和东/西 TCP/UDP 流量的第 4 层 (L4) 负载均…...

漏洞复现--IP-guard flexpaper RCE

免责声明: 文章中涉及的漏洞均已修复,敏感信息均已做打码处理,文章仅做经验分享用途,切勿当真,未授权的攻击属于非法行为!文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直…...

Electron-vue出现GET http://localhost:9080/__webpack_hmr net::ERR_ABORTED解决方案

GET http://localhost:9080/__webpack_hmr net::ERR_ABORTED解决方案 使用版本解决方案解决总结 使用版本 以下是我解决此问题时使用的electron和vue等的一些版本信息 【附】经过测试 electron 的版本为 13.1.4 时也能解决 解决方案 将项目下的 .electron-vue/dev-runner.js…...

Linux---(六)自动化构建工具 make/Makefile

文章目录 一、make/Makefile二、快速查看(1)建立Makefile文件(2)编辑Makefile文件(3)解释(4)效果展示 三、背后的基本知识、原理(1)如何清理对应的临时文件呢…...

谷歌:编写干净的代码以减少认知负荷

您是否曾经阅读过代码却发现很难理解?您可能正在经历认知负荷! 认知负荷是指完成一项任务所需的脑力劳动量。阅读代码时,您必须记住变量值、条件逻辑、循环索引、数据结构状态和接口契约等信息。随着代码变得更加复杂,认知负荷也…...

微信小程序display常用属性和子元素排列方式介绍

wxss中display常用显示属性与css一致,介绍如下: 针对元素本身显示的属性: displayblock,元素显示换行displayinline,元素显示换行,但不可设置固定的宽度和高度,也不可设置上下方向的margin和p…...

设计模式—结构型模式之代理模式

设计模式—结构型模式之代理模式 代理模式(Proxy Pattern) ,给某一个对象提供一个代理,并由代理对象控制对原对象的引用,对象结构型模式。 静态代理 比如我们有一个直播平台,提供了直播功能,但是如果不进行美颜,可能就比较冷清…...

C# PDF转HTML字符串

需要nuget安装Aspose.PDF插件,本文使用23.10.0版本 一、获取PDF文件,保存到某个路径;再读取返回字符串。 //html文件保存路径 string filePath dirPath "xxx.html"; if (!File.Exists(filePath)) {//获取pdf文件流Byte[] pdfBy…...

el-table解决数据过少小于高度有留白的问题

问题:给el-table设置个高度,高度为500px,之后就添加如下4条数据,那么底部就没数据,直接就空白了,本文章就是为了解决这个问题,如果底部留白那么就添加几条空数据就行了.如果数据已达到高度了那么就不会留白了 1.效果 这个空列可以根据高度来决定添加几个空格子去铺满列表&…...

vue实现无感刷新token

vue实现无感刷新token 1、前言2、实现思路2.1 方法一2.2 方法二2.3 方法三 3、可能遇到的问题3.1 问题一:如何防止多次刷新token3.2 问题二:同时发起两个或者两个以上的请求时,其他接口怎么解决 1、前言 最近在做vue3管理系统项目的时候&…...

竞赛选题 深度学习的动物识别

文章目录 0 前言1 背景2 算法原理2.1 动物识别方法概况2.2 常用的网络模型2.2.1 B-CNN2.2.2 SSD 3 SSD动物目标检测流程4 实现效果5 部分相关代码5.1 数据预处理5.2 构建卷积神经网络5.3 tensorflow计算图可视化5.4 网络模型训练5.5 对猫狗图像进行2分类 6 最后 0 前言 &#…...

Python高级语法----Python C扩展与性能优化

文章目录 1. 编写Python C扩展模块示例代码编译和运行运行结果2. 利用Cython优化性能示例代码编译和运行运行结果3. Python性能分析工具示例代码分析结果1. 编写Python C扩展模块 Python C扩展模块允许你将C语言代码集成到Python程序中,以提高性能。这对于计算密集型任务特别…...

行业洞察:分布式云如何助力媒体与娱乐业实现创新与增长?

过去数年,流媒体经历了蓬勃的发展过程,观众可以根据喜好收看自己所喜爱的节目内容,并希望在全球范围内访问内容。 繁荣的市场让媒体和娱乐行业的 IT 领导者们竞相发力,用更短的时间去创造互动且令人难忘的内容体验,力求…...

【多线程 - 05、后台线程】

后台线程 后台线程,它是在后台运行的,它的任务是为其他线程提供服务,这种线程被称为“后台线程(Daemon Thread)”,又称为“守护线程”或“精灵线程”。JVM的垃圾回收线程就是典型的后台线程。 后台线程的特…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...

pycharm 设置环境出错

pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...

前端高频面试题2:浏览器/计算机网络

本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...

书籍“之“字形打印矩阵(8)0609

题目 给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为:1,…...