Rust编程(三)生命周期与异常处理

生命周期

在这里插入图片描述

生命周期,简而言之就是引用的有效作用域。在大多数时候,我们无需手动的声明生命周期,因为编译器可以自动进行推导。生命周期的主要作用是避免悬垂引用,它会导致程序引用了本不该引用的数据:

{
	let r;
	{
		let x = 5;
		r = &x;
	}
	println!("R:{}",r);
}

这种情况r就是悬垂指针,r是引用的x,但是x的生命周期是到大括号结束就结束了,所以下面再使用r时,r就是一个悬垂指针。避免悬垂指针的方法就是:确保被引用的变量的生命周期长于引用本身。

fn main() {
    let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);
    //会报错,因为编译器不知道返回是x还是y,自然就没法对result进行生命周期分析
    println!("The longest string is {}", result);
}

fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
} 

对于一些复杂情况,编译器无法自己推导出生命周期,就需要我们自己进行生命周期标注:

&i32        // 一个引用
&'a i32     // 具有显式生命周期的引用
&'a mut i32 // 具有显式生命周期的可变引用

生命周期标注不对代码的逻辑起到任何作用,它自身并不具有什么意义,因为生命周期的作用就是告诉编译器多个引用之间的关系。

标注后的longest函数:

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    //这里告诉编译器,x和y的生命周期要长于`a
    //然后将二者的生命周期统一设定为较短的那个的生命周期
    //这样就不管是返回x还是y,result的生命周期都是一样的
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

当只与一个参数有关时,可以只标注一个的生命周期:

fn function<'a>(arg1:&'a mut String,arg2:& mut String) -> &'a mut String{
    return arg1;
}

fn main(){
    let mut s1 : String = String::new();
    let mut s2 : String = String::new();
    let s3 = function(&mut s1,&mut s2);
    println!("s3:{}",s3);
}

生命周期问题只针对于引用,主要是为了解决引用/借用还在,被引用/借用的没了的情况,对于move就没有这么麻烦,一旦move,直接生命周期就重新计算了,与之前的变量就没关系了。

结构体也有生命周期的要求,结构体内部有引用,被引用的对象的生命周期要长于结构体对象的生命周期:

struct ImportantExcerpt<'a> {
    part: &'a str,
}

fn main() {
    let novel1 = String::from("Call me Ishmael. Some years ago...");
    let first_sentence1 = novel1.split('.').next().expect("Could not find a '.'");
    let i = ImportantExcerpt {
        part: first_sentence1,
    }; //这种没有问题
    
    let i;
    {
        let novel2 = String::from("Call me Ishmael. Some years ago...");
        let first_sentence2 = novel2.split('.').next().expect("Could not find a '.'");
        i = ImportantExcerpt {
            part: first_sentence2,
        };
    }
    println!("{:?}",i); //这种就会报错,因为first_sentence2在大括号结束的时候生命周期已经结束了
}

函数情况下分为输入生命周期和输出生命周期,一些编译器可以推断出输入输出生命周期的情况,就不需要进行生命周期标注,编译器推断生命周期有三个规则:

  • 每一个引用参数都会获得独自的生命周期
    例如一个引用参数的函数就有一个生命周期标注: fn foo<'a>(x: &'a i32),两个引用参数的有两个生命周期标注:fn foo<'a, 'b>(x: &'a i32, y: &'b i32), 依此类推。

  • 若只有一个输入生命周期(函数参数中只有一个引用类型),那么该生命周期会被赋给所有的输出生命周期,也就是所有返回值的生命周期都等于该输入生命周期

  • 例如函数 fn foo(x: &i32) -> &i32,x 参数的生命周期会被自动赋给返回值 &i32,因此该函数等同于 fn foo<'a>(x: &'a i32) -> &'a i32

  • 若存在多个输入生命周期,且其中一个是 &self 或 &mut self,则 &self 的生命周期被赋给所有的输出生命周期。拥有 &self 形式的参数,说明该函数是一个 方法,该规则让方法的使用便利度大幅提升。
    更多关于生命周期的内容,请参考

函数返回/异常处理

在这里插入图片描述

Rust的函数返回为了解决是否有值的问题,引入了一个枚举类型Option,有值时返回Some(T),没值时返回None,再也不用绞尽脑汁如何思考返回-1或者None了。

enum Option<T> {
    Some(T),
    None,
}

Rust的异常分为可恢复异常Result,出了异常不直接崩溃,还可以根据异常的类别继续运行,类似于其他语言中函数返回了-1或者None。另一种是不可恢复异常panic,出了问题直接崩溃,类似于其他语言中的assert。

Result<T,E>

对应可以挽救的error,Result是一个枚举类型

enum Result<T, E> {
    Ok(T),
    Err(E),
}

使用案例:

fn plus_one(x: Option<i32>) -> Option<i32> {
    match x { //match就类似于C里面的switch语句
        None => None,
        Some(i) => Some(i + 1),
    }
}

let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);

当函数正常运行时,返回Ok包裹着的返回结果,当函数运行失败时,返回Err包裹的错误类型,
一般使用Result的工作流程就是:函数返回一个Result,然后使用match匹配结果:

use std::fs::File;
use std::io::ErrorKind;

fn main() {
    let f = File::open("hello.txt");

    let f = match f {
        Ok(file) => file,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => match File::create("hello.txt") {
                Ok(fc) => fc,
                Err(e) => panic!("Problem creating the file: {:?}", e),
            },
            other_error => panic!("Problem opening the file: {:?}", other_error),
        },
    };
}

Result也可以通过unwrap或者except转换为panic:

use std::fs::File;

fn main() {
    let f = File::open("hello.txt").unwrap();
    //不出问题就提取出来返回结果,出问题就直接panic
    let f = File::open("hello.txt").expect("Failed to open hello.txt");
    //跟上面一样的效果,不过会报错自定义的错误提示
}

panic

对应不可恢复error,出现panic代码直接崩溃

fn main() {
    panic!("crash and burn");
}

更多关于panic的请看Rust圣经

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

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

相关文章

【办公类-21-11】 20240327三级育婴师 多个二级文件夹的docx合并成docx有页码,转PDF

背景展示&#xff1a;有页码的操作题 背景需求&#xff1a; 实操课终于全部结束了&#xff0c;把考试内容&#xff08;docx&#xff09;都写好了 【办公类-21-10】三级育婴师 视频转文字docx&#xff08;等线小五单倍行距&#xff09;&#xff0c;批量改成“宋体小四、1.5倍行…

2024 MCM数学建模美赛2024年A题复盘,思路与经验分享:资源可用性与性别比例 | 性别比例变化是否对生态系统中的其他生物如寄生虫提供优势(五)

审题 第四问让我们探究性别比例变化是否对生态系统中的其他生物如寄生虫提供优势。这里我们可以把问题简化一下&#xff0c;只探究性别比例会不会对寄生虫提供优势。因为考虑太多生物&#xff0c;会使模型更复杂&#xff0c;我这个水平处理不了这么复杂的问题&#xff0c;是我…

整数在内存里面的存储

整数在内存里面的存储 整数在计算机里面的存储是按照二进制的方式进行存储 显示的时候是按照16进制的方法进行显示 1. 整数在内存中的存储在讲解操作符的时候&#xff0c;我们就讲过了下⾯的内容&#xff1a;整数的2进制表⽰⽅法有三种&#xff0c;即原码、反码和补码 三种…

案例研究|DataEase实现物业数据可视化管理与决策支持

河北隆泰物业服务有限责任公司&#xff08;以下简称为“隆泰物业”&#xff09;创建于2002年&#xff0c;总部设在河北省高碑店市&#xff0c;具有国家一级物业管理企业资质&#xff0c;通过了质量体系、环境管理体系、职业健康安全管理体系等认证。自2016年至今&#xff0c;隆…

FIM配置

FIM&#xff08;功能抑制管理器&#xff09; FIM模块根据DTC状态来确定对应功能是否要禁止 FiM_GetFunctionPermission通过RTE提供给SWC FiMFIDs FiMInhibitionConfigurations FiMInhFunctionIdRef&#xff1a;关联FIMID FiMInhInhibitionMask: FIM_LAST_FAILED Inh Event…

【氮化镓】p-GaN栅极退化的温度和结构相关性

论文总结&#xff1a; 本文献深入研究了带有p-GaN栅极的正常关断型(normally-off)高电子迁移率晶体管(GaN-HEMTs)在恒定电压应力下的时序退化行为。通过直流特性分析和温度依赖性分析&#xff0c;研究了故障时间(TTF)与应力温度和器件几何结构的依赖性。结果显示&#xff0c;p…

算法打卡day19

今日任务&#xff1a; 1&#xff09;235. 二叉搜索树的最近公共祖先 2&#xff09;701.二叉搜索树中的插入操作 3&#xff09;450.删除二叉搜索树中的节点 235. 二叉搜索树的最近公共祖先 题目链接&#xff1a;235. 二叉搜索树的最近公共祖先 - 力扣&#xff08;LeetCode&…

Android 自定义EditText

文章目录 Android 自定义EditText概述源码可清空内容的EditText可显示密码的EditText 使用源码下载 Android 自定义EditText 概述 定义一款可清空内容的 ClearEditText 和可显示密码的 PasswordEditText&#xff0c;支持修改提示图标和大小、背景图片等。 源码 基类&#xf…

大语言模型(LLM)token解读

1. 什么是token&#xff1f; 人们经常在谈论大模型时候&#xff0c;经常会谈到模型很大&#xff0c;我们也常常会看到一种说法&#xff1a; 参数会让我们了解神经网络的结构有多复杂&#xff0c;而token的大小会让我们知道有多少数据用于训练参数。 什么是token&#xff1f;比…

【C语言】Infiniband驱动init_dev_assign函数

一、注释 一个内核模块的初始化函数&#xff0c;用于分配和初始化某些资源。以下是对代码块的逐行中文注释&#xff1a; // 定义一个初始化设备分配的函数 static void init_dev_assign(void) {int i 1;spin_lock_init(&dev_num_str_lock); // 初始化自旋锁if (mlx4_fil…

量化交易入门(二十三)什么是MTM指标,原理是什么

MTM指标全称是Momentum指标,翻译为动量指标。它用来衡量市场价格在一定时间内上涨或下跌的幅度,属于趋势型指标。其计算公式是: MTM(N) 当前收盘价 - N日前的收盘价 其中N表示统计的周期数,常用参数有6日、12日和24日。 MTM指标的应用要点如下: 判断趋势强弱:MTM数值越大,表…

泛型的进阶

1 通配符 &#xff1f; 我们想调用fun函数帮我们打印&#xff0c;但由于不知道Message具体是什么类型&#xff0c;所以我们可以使用 &#xff1a; &#xff1f;即通配符 当我们将fun函数中改为Message<?>此时就不会报错 2 通配符的上界&#xff1a; <? extends 上…

如何使用 ArcGIS Pro 自动矢量化水系

对于某些要素颜色统一的地图&#xff0c;比如电子地图&#xff0c;可以通过图像识别技术将其自动矢量化&#xff0c;这里为大家介绍一下 ArcGIS Pro 自动矢量化水系的方法&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的电子地图数据&#…

二分练习题——123

123 二分等差数列求和前缀和数组 题目分析 连续一段的和我们想到了前缀和&#xff0c;但是这里的l和r的范围为1e12&#xff0c;明显不能用O(n)的时间复杂度去求前缀和。那么我们开始观察序列的特点&#xff0c;可以按照等差数列对序列进行分块。如上图&#xff0c;在求前10个…

虚拟机Linux(centos)安装python3.8(超详细)

一、Python下载 下载地址&#xff1a;https://www.python.org/downloads/source/ 输入下面网址即可直接下载&#xff1a; python3.8&#xff1a;https://www.python.org/ftp/python/3.8.0/Python-3.8.0.tgz python3.6&#xff1a;https://www.python.org/ftp/python/3.6.5/…

Chrome 插件 tabs API 解析

Chrome.tabs API 解析 使用 chrome.tabs API 与浏览器的标签页系统进行交互&#xff0c;可以使用此 API 在浏览器中创建、修改和重新排列标签页 Tabs API 不仅提供操作和管理标签页的功能&#xff0c;还可以检测标签页的语言、截取屏幕截图&#xff0c;以及与标签页的内容脚本…

Prompt Engineering的4 种方法

此为观看视频 4 Methods of Prompt Engineering 后的笔记。 从通用模型到专用模型&#xff0c;fine tuning&#xff08;微调&#xff09;和prompt engineering&#xff08;提示工程&#xff09;是2种非常重要的方法。本文深入探讨了prompt engineering的4种方法。 首先&#…

MySQL数据库的高级SQL语句与高级操作(2)

目录 一、子查询 1、语法: 2、以下例子均以图中两个表为基础 例子1&#xff1a;查询yun1班级大于85分的学生记录 例子2&#xff1a;将yun2班的学生记录放在一个单独的表中&#xff0c;叫yun2 例子3&#xff1a;教务处误把yun3班叫张丽的学生的成绩搞错了&#xff0c;应该为…

Machine Learning机器学习之向量机(Support Vector Machine,SVM)

目录 前言 算法提出背景&#xff1a; 核心思想&#xff1a; 原理&#xff1a; 应用领域&#xff1a; 一、支持向量机分类&#xff08;主要变体&#xff09; 二、构建常见的支持向量机模型 基于Python 中的 Scikit-learn 库构建线性支持向量机&#xff08;SVM&#xff09; 三、向…

Matplotlib数据可视化实战-2绘制折线图(2)

2.11营业额可视化 已知某学校附近一个烧烤店2022年每个月的营业额如下图所示。编写程序绘制折线图对该烧烤店全年营业额进行可视化&#xff0c;使用红色点画线连接每个月的数据&#xff0c;并在每个月的数据处使用三角形进行标记。 烧烤店营业额 月份123456789101112营业额/万…