Rust学习(四):作用域、所有权和生命周期:

Rust学习(四):作用域、所有权和生命周期:

Rust引入了所有权、作用域和生命周期等概念,并通过这些概念限制了各种量的转台和作用范围,Rust的作用域在所有编程语言中是最严格的,变量只能按照所有权和生命周期在某个代码块中生效,一旦超出这个范围,变量就会自动释放,Rust的作用域和C语言中的作用域一样,都是以“{}”作为边界,真正难以学习的是Rust的所有权机制和生命周期组成的作用域规则,下面我们重点介绍一下Rust中的所有权机制和生命周期。

1、所有权机制:

①定义:

所有权机制是Rust中的内存管理手段,类似于python中的垃圾回收机制或者是C/C++中的手动释放内存,Rust的编译器会根据一系列规则进行检查,倘若违反了规则,程序连编译器都无法通过(也造就了C/C++编译之后无法允许,Rust无法编译的梗)。

所有权机制规则如下:

  • 每个值只有一个所有者
  • 值在任意时刻都只有一个所有者
  • 当所有者离开作用域时,值会被自动丢弃。

实际上,Rust是将垃圾回收机制赋予了变量本身,这样不仅更安全,也更节约内存,维持了负载均衡,可以参考下面这个例子:

fn main() {
    let long = 10;
    {
        // 设置一个临时作用域:
        let a = 5;
        println!("a的值为:{}", a); 
    }  // a从临时作用域出来,根据所有权规则 a 被丢弃, println!("a:{}", a); 将会报错
    println!("long的值为:{}", long);
}

③移动和借用:

这里需要区分的是:移动是将变量的所有权转移给了新的变量,而借用所有权依然为原变量所拥有,新变量只是原来变量的一个引用:

fn main() {
    let x = "vertex".to_string();
    let y = x; // 将堆上的变量x的所有权转移给了变量 x 此时 再访问 x 将会报错
    
    let a = "geek".to_string();
    let b = &a;
    println!("{a}, {b}"); //将a通过引用借给了b,b不用于a的所有权,因此访问a和b都不会报错
    let c = &mut a; //设置可变引用
    // let d = &mut a; 错误!一个值只能有一个可变引用
}

④拷贝和克隆:

通过拷贝和克隆,相当于是将一本电子书复印了一份,这样原变量和新变量都拥有了对值得所有权(相当于原版和印刷版):

fn main() {
    let a = "string".to_string();
    let b = a.clone(); //克隆
    println!("{a} and {b}");
    
    let x = 10; //在栈上创建得变量
    let y = x;
    println!("{x} and {y}"); //在栈上创建得数据,rust默认实现了一个 Copy trait 相当于赋予了变量拷贝得功能,因此不需要再使用clone方法
}

2、生命周期:

熟悉C/C++的小伙伴,一定对指针不陌生,rust中的引用功能十分强大,用途上非常类似于C/C++中的指针,因此为了避免出现和C/C++中一样的悬垂指针(这里应该是悬垂引用),rust引入了生命周期的概念:

fn main() {
    let a;
    {
        let b = 10;
        a = &b;
    }
    println!("{a}");  //错误!出现了悬垂引用。
}

这里遇到了一个问题:b在它自身的作用域结束之后就被释放了,也就是说a被赋值给了一个指向为”空“的引用,这就发生了悬垂引用,编译器不会给我们的代码放行!

fn longest<'a>(x: &'a String, y: &'a String) ->&'a String {
    if x.len() < y.len() {
        y
    } else {
        x
    }
}

在编写了很多 Rust 代码后,Rust 团队发现在特定情况下 Rust 程序员们总是重复地编写一模一样的生命周期注解。这些场景是可预测的并且遵循几个明确的模式。接着 Rust 团队就把这些模式编码进了 Rust 编译器中,如此借用检查器在这些情况下就能推断出生命周期而不再强制程序员显式的增加注解。

这里我们提到一些 Rust 的历史是因为更多的明确的模式被合并和添加到编译器中是完全可能的。未来只会需要更少的生命周期注解。

被编码进 Rust 引用分析的模式被称为 生命周期省略规则lifetime elision rules)。这并不是需要程序员遵守的规则;这些规则是一系列特定的场景,此时编译器会考虑,如果代码符合这些场景,就无需明确指定生命周期。

省略规则并不提供完整的推断:如果 Rust 在明确遵守这些规则的前提下变量的生命周期仍然是模棱两可的话,它不会猜测剩余引用的生命周期应该是什么。编译器会在可以通过增加生命周期注解来解决错误问题的地方给出一个错误提示,而不是进行推断或猜测。

函数或方法的参数的生命周期被称为 输入生命周期input lifetimes),而返回值的生命周期被称为 输出生命周期output lifetimes)。

编译器采用三条规则来判断引用何时不需要明确的注解。第一条规则适用于输入生命周期,后两条规则适用于输出生命周期。如果编译器检查完这三条规则后仍然存在没有计算出生命周期的引用,编译器将会停止并生成错误。这些规则适用于 fn 定义,以及 impl 块。

第一条规则是编译器为每一个引用参数都分配一个生命周期参数。换句话说就是,函数有一个引用参数的就有一个生命周期参数:fn foo<'a>(x: &'a i32),有两个引用参数的函数就有两个不同的生命周期参数,fn foo<'a, 'b>(x: &'a i32, y: &'b i32),依此类推。

第二条规则是如果只有一个输入生命周期参数,那么它被赋予所有输出生命周期参数:fn foo<'a>(x: &'a i32) -> &'a i32

第三条规则是如果方法有多个输入生命周期参数并且其中一个参数是 &self&mut self,说明是个对象的方法 (method)那么所有输出生命周期参数被赋予 self 的生命周期。第三条规则使得方法更容易读写,因为只需更少的符号。

所有权和生命周期的概念确实复杂且难以理解,需要初学者花费大量的时间和精力!

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

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

相关文章

微服务(一)

目录 1.认识微服务 1.1.单体架构 1.2.微服务 1.3.SpringCloud SpringCloud版本 SpringBoot版本 2.服务注册和发现 2.1.注册中心原理 2.2.Nacos注册中心 2.3.服务注册 2.3.1.添加依赖 2.3.2.配置Nacos 2.4.服务发现 2.4.1.引入依赖 2.4.2.配置Nacos地址 2.4.3.发…

ubontu--cuDNN安装

1. 下载 cuDNN https://developer.nvidia.com/cudnn 2. 拷贝到服务器/home/<username>文件夹下 解压缩到当前文件夹&#xff1a; tar -xvf cudnn-linux-x86_64-9.5.1.17_cuda11-archive.tar.xz复制头文件和库文件到cuda安装目录/usr/local/cuda/ sudo cp /home/usern…

Vue 批量注册组件实现动态组件技巧

介绍 Vue 动态组件的应用场景很多,可应用于动态页签,动态路由等场景,其核心原理是批量注册。在Vue2和Vue3中实现原理相同,只是语法略有差异。 Vue2 实现 基于 webpack require.context() 是webpack提供的一个自动导入的API 参数1&#xff1a;加载的文件目录 参数2&#xff…

WEB攻防-通用漏洞SQL读写注入MYSQLMSSQLPostgraSQL

知识点&#xff1a; 1、SQL注入-MYSQL数据库&#xff1b; 2、SQL注入-MSSQL数据库&#xff1b; 3、SQL注入-PostgreSQL数据库&#xff1b; 首先要找到注入点 详细点&#xff1a; Access无高权限注入点-只能猜解&#xff0c;还是暴力猜解 MYSQL&#xff0c;PostgreSQL&am…

NocoBase 本周更新汇总:提升工作流易用性

汇总一周产品更新日志&#xff0c;最新发布可以前往我们的博客查看。 NocoBase 目前更新包括两个分支&#xff1a;main 和 next 。 main &#xff1a;截止目前最稳定的版本&#xff0c;推荐安装此版本。 next&#xff1a;内测版&#xff0c;包含一些未发布的新特性&#xff…

python高级之面向对象编程

一、面向过程与面向对象 面向过程和面向对象都是一种编程方式&#xff0c;只不过再设计上有区别。 1、面向过程pop&#xff1a; 举例&#xff1a;孩子上学 1. 妈妈起床 2. 妈妈洗漱 3. 妈妈做饭 4. 妈妈把孩子叫起来 5. 孩子起床 6. 孩子洗漱 7. 孩子吃饭 8. 妈妈给孩子送学校…

❤React-React 组件基础(类组件)

❤React-React 组件基础 1、组件化开发介绍 组件化开发思想&#xff1a;分而治之 React的组件按照不同的方式可以分成类组件&#xff1a; 划分方式一&#xff08;按照组件的定义方式&#xff09; 函数组件(Functional Component )和类组件(Class Component)&#xff1b; …

在Java中使用ModelMapper简化Shapefile属性转JavaBean实战

目录 前言 一、原始的处理办法 1、使用Set方法来转换 2、使用构造方法转换 二、基于ModelMapper的动态转换 1、ModelMapper简介 2、集成到项目中 3、Shapefile属性读取 三、总结 前言 在现代软件开发中&#xff0c;尤其是在多层架构中&#xff0c;经常需要将数据从一个…

Arduino IDE Windows 系统 离线安装 esp32 开发板 亲测好用。

1、前提条件需要具备特殊网络。 2、官方文档地址&#xff1a;Installing - - — Arduino ESP32 latest documentation 3、系统&#xff1a;Windows10 Arduino IDE 版本2.3.3 之前安装的esp32开发板的版本是2.0.13&#xff0c;由于之前没有接触过esp32开发&#xff0c;也没…

期权懂|请问如何用期权进行风险管理?

期权小懂每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 请问如何用期权进行风险管理&#xff1f; 一、期权可以选择交易活跃的期权合约进行风险管理&#xff1a; 对于初级投资者来说&#xff0c;选择交易活跃的期权合约是非常重要的。…

GNU构建系统和Autotool

1、前言 经常使用Linux的开发人员或者运维人员&#xff0c;可能对configure->make->make install相当熟悉。事实上&#xff0c;这叫GNU构建系统&#xff0c;利用脚本和make程序在特定平台上构建软件。这种方式成为一种习惯&#xff0c;被广泛使用。本文从用户视角和开发…

NLP论文速读|ScPO:自我一致性的偏好优化(Self-Consistency Preference Optimization)

论文速读|Self-Consistency Preference Optimization 论文信息&#xff1a; 简介&#xff1a; 这篇论文试图解决的问题是如何在没有人类标注数据的情况下&#xff0c;提高大型语言模型&#xff08;LLMs&#xff09;在复杂推理任务上的性能。现有的自我对齐技术往往因为难以分配…

【前端学习指南】Vue computed 计算属性 watch 监听器

&#x1f36d; Hello&#xff0c;我是爱吃糖的范同学 &#x1f534; 想把自己学习技术的经历和一些总结分享给大家&#xff01; &#x1f534; 通过这样的方式记录自己成长&#xff0c;同时沉淀自己的技术&#xff0c;我会把所有额外的时间和经历投放到CSDN和公众号&#xff0…

自动驾驶合集(更新中)

文章目录 车辆模型控制路径规划 车辆模型 车辆模型基础合集 控制 控制合集 路径规划 规划合集

vcenter service基本异常处理

服务&#xff1a;vcenter service 版本&#xff1a; 7.0.3 问题描述&#xff1a;无法访问vcenter ui 排障思路&#xff1a; 1. 登入vcenter所在服务器执行基础排查&#xff1a;内存、cpu、磁盘、网络等&#xff0c;发现磁盘日志目录已经爆满&#xff0c;删除180天前的日志恢…

Background Tasks Kit(后台任务开发服务)

11_13日学习笔记 Background Tasks Kit&#xff08;后台任务开发服务&#xff09; Background Tasks Kit简介 设备返回主界面、锁屏、应用切换等操作会使应用退至后台。 应用退至后台后&#xff0c;如果继续活动&#xff0c;可能会造成设备耗电快、用户界面卡顿等现象。 为了…

modbus协议 Mthings模拟器使用

进制转换 HEX 16进制 (0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F表示0-15) dec 10进制 n(16进制) -> 10 abcd.efg(n) d*n^0 c*n^1 b*n^2 a*n^3 e*n^-1 f*n^-2 g*n^-3&#xff08;10&#xff09; 10 -> n(16进制) Modbus基础概念 高位为NUM_H&…

Python多进程间通讯(包含共享内存方式)

文章目录 1 通过非共享内存配合队列方式2 通过共享内存配合队列方式 注&#xff1a;本博文测试环境为Linux系统。 1 通过非共享内存配合队列方式 下面是一个常见的生产者与消费者的模式示例&#xff0c;这里分别启动了两个子进程&#xff0c;一个为生产者&#xff08;producer…

YOLOv11实战宠物狗分类

本文采用YOLOv11作为核心算法框架&#xff0c;结合PyQt5构建用户界面&#xff0c;使用Python3进行开发。YOLOv11以其高效的特征提取能力&#xff0c;在多个图像分类任务中展现出卓越性能。本研究针对5种宠物狗数据集进行训练和优化&#xff0c;该数据集包含丰富的宠物狗图像样本…

游戏引擎学习第八天

视频参考: https://www.bilibili.com/video/BV1ouUPYAErK/ 理解下面的代码 关于虚函数 代码分解 结构体 foo 的定义&#xff1a; struct foo {int32 X;int64 Y;virtual void Bar(int c); };foo 结构体有两个成员变量&#xff1a;X&#xff08;int32 类型&#xff09;和 Y&…