【Rust自学】9.2. Result枚举与可恢复的错误 Pt.1:match、expect和unwrap处理错误

news2025/1/5 8:35:57

喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)

9.2.1. Result枚举

通常情况下,错误都没有严重到需要停止整个程序的地步。某个函数之所以运行失败或者是遇到错误通常是由一些可以简单解释并做出响应的原因引起的。比如说程序要打开某个文件,但是这个文件并不存在,这个时候通常会考虑创建这个文件而不是直接终止程序。

Rust提供了Result这个枚举类型来处理这种可能失败的情况。它的定义是:

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

它有两个泛型的类型参数,一个是T一个是E,它有两个变体,每个都关联了数据,OK关联了T,Err关联了E。泛型在第十章会讨论,现在只需要知道T是操作成功的情况下,OK变体里返回的数据的类型;E是在操作失败的情况下,Err变体里返回的错误的类型。

看个例子:

use std::fs::File;  
fn main() {  
    let f = File::open("6657.txt");  
}

这个代码的操作是打开文件,但这个文件不一定存在,所以说函数的运行可能会失败,所以File::open这个函数的返回值是Result枚举。这个Result里面第一个参数是std::fs::File,也就是文件类型(成功的时候返回);而第二个是std::io::Error,也就是io错误(失败的时候返回)

9.2.2. 用match处理Result

Option枚举一样,Result及其变体也是由预导入模块(prelude)带入作用域的,在写代码时不需要额外的引入。如下例:

use std::fs::File;  
fn main() {  
    let f = File::open("6657.txt");  
    let f = match f {  
        Ok(file) => file,  
        Err(e) => panic!("Error: {}", e),  
    };  
}

如果返回的值是Ok,那么就把它所关联的值绑定到file上再返回回去赋给f;如果返回的值是Err,那么就把错误信息绑定在e上由panic!宏打印出来并停止程序。

9.2.3. 匹配不同的错误

我们把上面的例子完善一下,如果出现找不到的情况,就创建这个文件,如果连创建都不成功或者是出现了除了找不到意外的情况(比如没有权限打开),才触发panic!

use std::fs::File;  
use std::io::ErrorKind;  
  
fn main() {  
    let f = File::open("6657.txt");  
    let f = match f {  
        Ok(file) => file,  
        Err(e) => match e.kind() {  
            ErrorKind::NotFound => match File::create("6657.txt") {  
                Ok(fc) => fc,  
                Err(e) => panic!("Problem creating file: {:?}", e),  
            },  
            other_error => panic!("Problem opening file: {:?}", other_error),  
        },  
    };  
}
  • 在最外层仍然是如果f的值是Ok就把文件内容返回给f
  • 但在处理Err变体时有不同,Err所附带的数据的类型是std::io::Error,这个struct上有一个.kind()方法,通过这个方法可以获得std::io::ErrorKind这个类型值,它也是一个枚举,也是由标准库提供的,它里面的变体是用来描述io操作可能引起的不同错误
  • ErrorKind里面有一个变体ErrorKind::NotFound,表示文件不存在,这个时候就应该创建文件,在下面我们再讨论创建文件。除了ErrorKind::NotFound,也可能有其他错误(比如说没有权限读取),这里把其他错误赋给了other_error这个值,并由panic!打印出来然后停止程序。
  • 对于创建文件,可以使用File::create()这个函数,其参数就是文件名。而创建文件本身也有可能会失败(比如没权限),所以File::create()的返回值也是Result类型,那就再用一个match表达式来处理,如果是OK(创建成功),那就把OK关联的值,也就是这个新创建的文件呢的内容(内容肯定是空的,因为是新创建的)绑定在fc这个变量上返回赋给f;如果是Err(创建失败),就把Err所关联的错误信息绑定在e上用panic!打印出来并停止程序。

match确实用的比较多,但也比较原始,这里的套娃是其可读性大大降低(虽然对比其他语言可能可读性还要高一些)。而在第13章会讲一个概念叫做闭包(closure),Result类型有很多方法接受闭包作为参数,而且这些方法都是使用match实现的,能够使得代码更加简洁,我把使用闭包的代码例写在这里,但现在不会讲,到13章才会讲。

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

fn main() {
    let greeting_file = File::open("6657.txt").unwrap_or_else(|error| {
        if error.kind() == ErrorKind::NotFound {
            File::create("6657.txt").unwrap_or_else(|error| {
                panic!("Problem creating the file: {error:?}");
            })
        } else {
            panic!("Problem opening the file: {error:?}");
        }
    });
}

9.2.4. unwrap方法

match表达式确实灵活有用,但写出来的代码也确实复杂了一些,而Result这个枚举类型本身也定义了许多的辅助方法来应对各式各样的任务,其中有一个常用的方法叫unwrap

如果unwrap接收到了OK,那么它就会把OK附带的值返回;而如果接收到了Err,那么unwrap就会调用panic!宏。比如说用unwrap重写9.2.2中的代码:

use std::fs::File;  
  
fn main() {  
    let f = File::open("6657.txt").unwrap();  
}

unwrap就相当于match表达式的快捷方法。它的缺点就是错误信息不可以自定义。

9.2.5. expect方法

那如果我想要unwrap的快捷性,又想要自定义错误信息怎么办?针对这种情况,Rust提供了expect方法,如果你有印象的话,在第一章的猜数游戏中就用过这种方法。

试试用expect重写unwrap的代码例:

use std::fs::File;  
  
fn main() {  
    let f = File::open("6657.txt").expect("file not found");  
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

虚拟机Centos下安装Mysql完整过程(图文详解)

目录 一. 准备工作 1. 设置虚拟机静态IP 2. 卸载Mysql 3. 给CentOS添加rpm源 二. 安装MySQL 1. 安装mysql服务 2. 启动mysql服务 3. 开启MySQL开机自启动 4. 查看mysql服务状态 5. 查看mysql初始密码 6. 登录mysql &#xff0c;修改密码 7. 允许外部访问MySQL数据库…

SwiftUI:多语言实现富文本插值

实现的UI需求&#xff1a; 要求&#xff1a; 英文显示&#xff1a;3068 people have joined this plan today! 中文显示&#xff1a;今日有 3068 人已加入此计划&#xff01; 实现代码&#xff1a; Text(AttributedString(localized:"**\(payPeoples)** people have joi…

中巨伟业推出高安全高性能32位智能卡内核可编程加密芯片SMEC88SP/ST

1、产品特性  以最高安全等级的智能卡芯片内核为基础&#xff0c;具有极高的软硬件安全性  实现客户关键功能或算法代码下载&#xff0c;用户可以灵活实现自有知识产权的保护  标准 SOP8、SOT23-6 封装形式&#xff0c;器件封装小  标准 I2C 接口&#xff0c;具有接…

部署SenseVoice

依赖 Conda cuda pythor 查看GPU版本-CSDN博客 创建虚拟conda环境 conda create --name deeplearn python3.10 conda activate deeplearn git clone https://github.com/FunAudioLLM/SenseVoice.git cd SenseVoice pip install -r requirements.txt pip install gradio pip …

微信流量主挑战:用户数30!新增文档转化功能,解决docker运行jar包报错SimSun找不到的问题(新纪元5)

哎呀&#xff0c;今天忙到飞起&#xff0c;文章晚点更新啦&#xff01;不过好消息是&#xff0c;我们的小程序用户终于突破30啦&#xff0c;感谢大家的支持&#xff01;而且&#xff0c;大家期待已久的文档转化功能明天就要上线啦&#xff0c;目前支持word转pdf&#xff0c;pdf…

操作系统课后题总复习

目录 一、第一章 1.1填空题 1.2单项选择题 1.3多项选择题 1.4判断题 1.5名词解释 1.6简答题 二、第二章 2.1填空题 2.2单项选择题 2.3 多项选择题 2.4判断题 2.5名词解释 2.6简答题 三、第三章 3.1填空题 3.2单项选择题 3.3多项选择题 3.4判断题 3.5名词解…

C语言期末复习笔记(下)

目录 九、指针 1.指针变量的定义和初始化 2.间接寻址符* 3.按值调用和按址调用 4.实例 5.函数指针 6.指针变量和其它类型变量的对比 十、字符串 1.字符串常量 2.字符串的存储 3.字符指针 4.字符串的访问和输入/输出 5.字符串处理函数 &#xff08;1&#xff09;str…

保姆级教程Docker部署ClickHouse镜像

目录 1、安装Docker及可视化工具 2、创建挂载目录 3、获取配置文件 4、运行ClickHouse容器 5、Compose运行ClickHouse容器 6、查看ClickHouse运行状态 7、安装包部署 1、安装Docker及可视化工具 Docker及可视化工具的安装可参考&#xff1a;Ubuntu上安装 Docker及可视化…

飞牛私有云APP结合cpolar内网穿透技术实现远程连接本地fnOS NAS

文章目录 前言1. 本地连接测试2. 飞牛云安装Cpolar3. 配置公网连接地址4. 飞牛云APP连接测试5. 固定APP远程地址6. 固定APP地址测试 前言 现在生活和工作中的各种设备都变得越来越智能&#xff0c;而数据存储的需求也随之剧增。想象一下&#xff1a;你正在外地出差&#xff0c…

计算机网络 (17)点对点协议PPP

一、PPP协议的基本概念 PPP协议最初设计是为两个对等节点之间的IP流量传输提供一种封装协议&#xff0c;它替代了原来非标准的第二层协议&#xff08;如SLIP&#xff09;。在TCP/IP协议集中&#xff0c;PPP是一种用来同步调制连接的数据链路层协议&#xff08;OSI模式中的第二层…

RC充电电路仿真与分析

RC充电原理 下图是一个常见的RC充电电路&#xff1a;&#xff08;假设R10K&#xff0c;C100nF&#xff09; SW断开时&#xff0c;这个电路处于断路状态&#xff0c;C既没有充电也没有放电&#xff1b;SW闭合时&#xff0c;直流电源5V为电容C充电&#xff1b; 充电时电容两端…

全新免押租赁系统助力商品流通高效安全

内容概要 全新免押租赁系统的推出&#xff0c;可以说是一场商品流通领域的小革命。想象一下&#xff0c;不再为押金烦恼&#xff0c;用户只需通过一个简单的信用评估&#xff0c;就能快速租到所需商品&#xff0c;这种体验简直令人惊喜&#xff01;这个系统利用代扣支付技术&a…

c++领域展开第八幕——类和对象(下篇 初始化列表、类型转换、static成员)超详细!!!!

文章目录 前言一、初始化列表二、类型转换三、static成员总结 前言 上篇博客我们实现了一个简单的日期类&#xff0c;基本的类和对象是清楚了 今天我们再来学习后面的一些类和对象的语法&#xff0c;慢慢的完善所学的东西 fellow me 一、初始化列表 • 之前我们实现构造函数时…

Linux-Ubuntu之RGBLCD显示屏

Linux-Ubuntu之RGBLCD显示屏 一&#xff0c;实现原理二&#xff0c;驱动代码三&#xff0c;总结1.c语言知识 一&#xff0c;实现原理 采用的是4.3寸 800480显示屏&#xff0c;即每行有800个像素点&#xff0c;每列有480个像素点&#xff0c;外接时钟信号&#xff0c;控制刷新频…

JVM 主要组成部分与内存区域

一、JVM 主要组成部分&#xff1a; JVM的主要包含两个组件和两个子系统&#xff0c;分别为&#xff1a; &#xff08;1&#xff09;本地库接口(Native Interface)&#xff1a;与native lib(本地方法库)交互&#xff0c;融合其他编程语言为Java所用&#xff0c;是与其它编程语言…

如何在鸿蒙本地模拟器中使用HDC工具

引言 HDC是指华为设备连接&#xff08;Huawei Device Connector&#xff09;工具。它的作用类似Android开发的ADB工具。在华为鸿蒙&#xff08;HarmonyOS&#xff09;操作系统的开发过程中&#xff0c;HDC工具起到了至关重要的作用。它允许开发者在开发主机&#xff08;如 PC&…

ruoyi 分页 查询超出后还有数据; Mybatis-Plus 分页 超出后还有数据

修改&#xff1a;MybatisPlusConfig 类中 分页合理化修改为&#xff1a;paginationInnerInterceptor.setOverflow(false);

Unity中实现转盘抽奖效果(二)

如果要使转盘停止时转到到指定位置&#xff0c;应该如何做&#xff1f; 实现思路&#xff1a; 也就是在需要停止的分数的区间范围内&#xff0c;随机一个角度值&#xff0c;然后反推需要在哪个角度开始减速&#xff0c;如果转盘的当前角度和需要开始减速的角度有差值&#xf…

苍穹外卖04——Redis初入门 在店铺打烊or营业状态管理功能中的使用

Redis入门 redis简介 它以键值对的形式存储数据在内存中,并且以极高的性能和灵活性而著称,通常用于缓存、消息代理以及持久化数据。 - 基于内存存储,读写性能高- 适合存储热点数据(热点商品、资讯、新闻)- 企业应用广泛Windows版下载地址:https://github.com/microsoft…

深度学习每周学习总结R2(RNN-天气预测)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客R5中的内容&#xff0c;为了便于自己整理总结起名为R2&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 目录 0. 总结1. RNN介绍a. 什么是 RNN&#xff1f;RNN 的一般应用场景 b. 传统 RNN …