RUST 每日一省:生命周期作用域

news/2024/11/15 8:41:42/

生命周期

        一个变量的生命周期就是它从创建到销毁的整个过程。

作用域
        我们声明的每个变量都有作用域。作用域其实是变量和值存在的环境。作用域是由一对花括号表示的。例如,使用块表达式会创建一个作用域,即任何以花括号开头和结尾的表达式。此外,作用域支持互相嵌套,并且可以在子作用域中访问父作用域的元素,但反过来不行。

{let a = "hello";    ----------+-- a的作用域let b = 1;          -----+--b |{                        |    |let c = true;   ---+--c  |    ||     |    |---+     |    |}                        |    |---------+    |--------------+
}

        当作用域结束时,作用域内定义的变量都会运行相关代码以释放资源。对于在堆栈上分配的数据,可以轻松地判定变量是否存续。对在堆上分配的值, drop 方法会被放在作用域结束标记}之前调用。但这里是隐式的,可以避免程序员忘记释放值。 drop 方法来自 Drop 特征,它是为 Rust 中大部分堆分配类型实现的,可以轻松地自动释放资源。

生命周期&作用域

        Rust的生命周期是基于作用域的,我们可以认为变量的生命周期就是其作用域; 编译器能自动识别作用域内这些变量的生命周期,方便进行管理。其实生命周期纯粹是一个编译期构造,它可以帮助编译器确定某个引用有效的作用域,并确保它遵循借用规则。它可以跟踪诸如引用的来源,以及它们是否比借用值生命周期更长这类事情。Rust 中的生命周期能够确保引用的存续时间不超过它指向的值。生命周期并不是作为开发人员要用到的,而是编译器使用和推断引用的有效性时会用到的。

{let a = "hello";    ----------+-- a生命周期let b = 1;          -----+--b |{                        |    |let c = true;   ---+--c  |    ||     |    |---+     |    |}                        |    |---------+    |--------------+
}

所有权的转移 

        由于变量会在作用域结束时,会自动释放。如果我们需要在其作用域外继续使用它,要么转移所有权, 要么按位复制,就可以继续使用, 这取决于该变量是复制语义还是移动语义的。

        如果有其他变量进入了作用域,也是会发生所有权的变化;要么转移所有权, 要么按位复制, 这取决于该变量是复制语义还是移动语义的。

{let a = "hello".to_string();     let b = 1;   let c_out;  let d_out;        {                         let c_in = 2;  let d_in = "world".to_string();                    a;b;c_out = c_in;d_out = d_in;}     //println!("a:{}",a);     println!("b:{}",b);   println!("c_out:{}",c_out);//println!("c_in:{}",c_in);//println!("d_in:{}",d_in);   println!("d_out:{}",d_out);   
}b:1
c_out:2
d_out:world

        如果我们要把打印a的注释去掉,就会产生如下错误,a进入子作用域之后,发生所有权转移,在自作用结束的时候,释放了a,所以我们继续使用就会报错了。

 去掉c_in的打印,则会产生如下错误,c_in也是如此。

创建新的作用域

  • 可以使用块表达式(花括号)创建作用域。
{let a = "hello".to_string();     let b = 1;   let c_out;  let d_out;        {                         let c_in = 2;  let d_in = "world".to_string();                    a;b;c_out = c_in;d_out = d_in;}     //println!("a:{}",a);     println!("b:{}",b);   println!("c_out:{}",c_out);//println!("c_in:{}",c_in);//println!("d_in:{}",d_in);   println!("d_out:{}",d_out);   
}
  • match匹配也会产生一个作用域。
  • for、 loop以及while循环语句均可以创建新的作用域。
  • if let块和while let块也会创建新的作用域。

        这三者都是类似,我们以match为例,演示一下。如果t换成是Some(6),就没有问题,因为t是Option<i32>,具有复制语义了。

fn main(){let t = Some("test".to_string());match t{Some(v) => (),None => (),}//println!("t:{}",t);
}

去掉注释之后,报错如下,说明t已经在Some(v)=> ()发生了所有权的转移,然后在作用域结束时被释放掉了;

  • 函数体本身是独立的作用域。

由于String是移动语义,当它作为参数传入f函数后,发生了所有权转移,如果在main函数中再次调用就会发生错误。

fn f(t:String){println!("{:?}",t);
}
fn main(){let t = Some("test".to_string());f(t);//println!("{:?}",t);
}

  • 闭包

闭包会创建新的作用域, 对于环境变量来说有以下三种捕获方式:
· 对于复制语义类型, 以不可变引用(&T) 来捕获。
· 对于移动语义类型, 执行移动语义(move) 转移所有权来捕获。
· 对于可变绑定, 如果在闭包中包含对其进行修改的操作, 则以可变引用(&mut) 来捕获。


fn main(){let t = Some("test".to_string());let c = |i: i32|{//println!("{:?},{:?}",t,i);t;};c(0);//println!("{:?}",t);
}

这里还有一个比较有意思的地方,就是println!("{:?},{:?}",t,i);如果在闭包里只有这一句;没有t; 则不会发生所有权的转移;即println不发生所有权的转移,他表面调用的时候t,实际的参数&t;


http://www.ppmy.cn/news/52817.html

相关文章

如何在模拟器里面脱360的壳

1.准备环境 1.夜神模拟器 2.pyhton3.8 3.frida的版本 16.0.17 4.frida-dexdump 2.设置adb连接 我们打开夜神模拟器所在的文件夹&#xff0c;里面有自带的adb&#xff0c;我们在这个文件夹里面打开cmd。在里面链接上夜神模拟器。 adb devices 我这边显示链接成功了。 3.…

大学生蓝桥杯

蓝桥杯 简介比赛科目 简介 全国普通高校学科竞赛排行榜&#xff0c;是由中国高等教育学会“高校竞赛评估与管理体系研究”专家工作组研究发布的竞赛评估体系&#xff0c;已经连续六年发布&#xff0c;是高校提高人才培养质量的服务性参考信息&#xff0c;是检验高校创新人才培…

【C语言】函数讲解(下)

【C语言】函数讲解&#xff08;下&#xff09; 1.函数的声明和定义1.1函数声明1.2函数定义 2.函数的嵌套调用和链式访问2.1嵌套调用2.2链式访问 3.函数递归3.1什么是递归3.2递归的两个必要条件3.2.1练习13.2.2练习2 3.3递归与迭代3.3.1练习13.3.2练习2 所属专栏&#xff1a;C语…

Android内存泄漏问题排查分析及常见解决方案

什么是内存泄漏&#xff1a; 在Android开发过程中&#xff0c;当一个对象已经不需要再使用了&#xff0c;本该被回收时&#xff0c;而另个正在使用的对象持有它引用从而导致它不能被回收&#xff0c;这就导致本该被回收的对象不能被回收而停留在堆内存中&#xff0c;内存泄漏就…

【SCI征稿】计算机科学类SCI, 领域广,2-3个月录用~

一、期刊简介&#xff1a; 4区计算机科学类SCI 【期刊概况】IF:0.5-1.0, JCR4区, 中科院4区&#xff1b; 【终审周期】走期刊部系统&#xff0c;2-3个月左右录用&#xff1b; 【检索情况】SCI在检&#xff1b; 【数据库收录年份】2007年&#xff1b; 【国人占比】12.35%…

c++算法——vector

vector vector 是标准模板库的一个容器&#xff0c;直接翻译为“向量”&#xff0c;一般来成“可变长数组”&#xff0c;也即“长度会根据需要而变化的数组”。在竞赛中有些题目需要很大的很大的数组&#xff0c;而有些还用不上就需要用到 vector 。 使用 vector 首先要加#incl…

Binder与 四大组件工作原理 Service、BroadCastReceiver、ContentProvider

Service 工作原理 Service有两套流程&#xff0c;一套是启动流程&#xff0c;另一套是绑定流程。我们做App开发的同学都应该知道 1&#xff09;在新进程启动Service 我们先看Service启动过程&#xff0c;假设要启动的Service是在一个新的进程中&#xff0c;分为5个阶段&#…

024:Mapbox GL加载image图像文件

第024个 点击查看专栏目录 本示例的目的是介绍演示如何在vuemapbox中加载image图像文件。图像源。 “url”值包含图像位置。“坐标”数组包含按顺时针顺序列出的图像角的 [longitude, latitude] 对&#xff1a;左上角、右上角、右下角、左下角。 直接复制下面的 vuemapbox源代…