30天拿下Rust之错误处理

概述

        在软件开发领域,对错误的妥善处理是保证程序稳定性和健壮性的重要环节。Rust作为一种系统级编程语言,以其对内存安全和所有权的独特设计而著称,其错误处理机制同样体现了Rust的严谨与实用。在Rust中,错误处理通常分为两大类:不可恢复的错误和可恢复的错误。这两种错误的处理方式在Rust的设计哲学中扮演着不同的角色,并且适用于不同的场景。

不可恢复的错误

        不可恢复的错误是指那些由于严重问题,导致程序无法继续执行的情况。这类错误通常是由于编程错误、资源耗尽、或者外部系统问题导致的。在Rust中,不可恢复的错误通过panic!宏来触发。

        当panic!被调用时,程序会立即停止当前的执行流程,并打印出一条错误消息,然后退出程序。因为panic!会导致程序崩溃,所以它通常只在开发过程中用于检测那些不应该发生的严重错误。

        在下面的示例代码中,如果除数b为0,会通过panic!宏来触发不可恢复的错误,并打印错误消息“Division by zero”。panic!被调用后,程序会立即终止,因此,后面的println!不会执行。

fn divide(a: i32, b: i32) -> i32 {
    if b == 0 {
        panic!("Division by zero");
    }
    a / b
}

fn main() {
    let value = divide(66, 0);
    println!("{}", value);
}

        注意:在生产代码中,应当尽量避免使用panic!,因为它会导致程序不稳定和不可靠。相反,应该使用下面介绍的可恢复的错误机制来优雅地处理可能出现的错误,并确保程序在遇到问题时,能够以一种可预测和可控的方式做出响应。

可恢复的错误

        可恢复的错误是指那些可以通过某种方式修正或处理的错误,通常不会导致程序完全崩溃。在Rust中,这类错误通常通过Result枚举类型来表示。Result有两个可能的变体:Ok用于表示操作成功的结果,而Err用于表示错误。

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

        使用Result枚举类型,函数可以显式地表示它们可能失败,并返回一个错误值。调用这些函数的代码,可以选择如何处理这些错误,比如:重试、提供默认值、或者将错误传递给上层调用者。这种错误处理机制允许程序在发生错误时保持运行,并可能从错误中恢复。

        在下面的示例代码中,我们调用File::open方法尝试打开名为“CSDN.txt”的文件。这个方法返回一个Result类型,其中Ok变体包含文件句柄(如果文件打开成功),而Err变体包含错误信息(如果文件打开失败)。

use std::fs::File;

fn main() {
    let file_handle = File::open("CSDN.txt");
    match file_handle {
        Ok(file) => {
            println!("open successfully");
        },
        Err(err) => {
            println!("failed: {}", err);
        }
    }
}

        如果想将一个可恢复的错误按照不可恢复的错误处理,Result类提供了两个方法:unwrap()和expect()。这两个方法是用于处理Result或Option类型的便捷方法,用于从这些类型中提取出内部值,但当值不存在(对于Option)或是一个错误状态(对于Result)时,都会导致程序panic。如果Option是None或者Result是Err(E),则unwrap()会触发panic,并打印出默认的panic!消息。expect()方法与unwrap()方法类似,但它允许我们自定义在panic时输出的错误消息。

fn main() {
    let opt_value: Option<i32> = Some(66);
    let value = opt_value.unwrap();
    println!("{}", value);

    let result: Result<i32, String> = Err("not valid".to_string());
    result.expect("failed");
}

        注意:在非生产环境或者确定不会出现错误的情况下可以使用unwrap()方法和expect()方法,但在实际项目开发中应尽量避免。

?运算符

        Rust提供了一个便捷的?运算符,用于简洁地传播错误。当Result类型变量出现在?后面时,如果它是Ok值,则解包其内部的值;如果是Err值,则从当前函数返回该错误。

        在下面的示例代码中,?操作符用于简化错误处理。如果在其前面的操作File::open和read_to_string返回Err变体,则整个表达式会立即返回该错误。这使得代码更加简洁,但也可能隐藏一些复杂的错误处理逻辑。在需要更精细控制错误处理的情况下,应该使用完整的match表达式或if let语句。

use std::fs::File;
use std::io::Read;

fn read_file(filename: &str) -> Result<String, std::io::Error> {
    let mut file = File::open(filename)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

fn main() {
    let result = read_file("CSDN.txt");
    match result {
        Ok(contents) => println!("content is: {}", contents),
        Err(e) => {
            println!("read file failed: {}", e);
        }
    }
}

自定义错误

        在Rust中,可以通过实现std::error::Error trait来创建自定义错误类型。这允许我们定义自己的错误类型,并能够更具体地描述程序中可能发生的错误情况。

        自定义错误类型通常包含一个或多个字段,这些字段可以包含有关错误的额外信息。通过实现Error trait,我们可以控制错误消息的格式,并且错误类型可以与其他期望Error trait的Rust错误处理机制一起工作。

        在下面的示例代码中,MyCustomError是一个简单的结构体,它包含一个描述错误的String字段。我们实现了Error trait,使得MyCustomError可以作为错误类型被使用。此外,我们还实现了fmt::Display trait,以定义错误打印时应该显示的字符串。process函数模拟了一些可能失败的操作,并在失败时返回一个MyCustomError实例。在main函数中,我们调用process函数并处理其返回的结果,并打印输出相应的信息。

use std::error::Error;
use std::fmt;

// 自定义错误类型
#[derive(Debug)]
struct MyCustomError {
    desc: String,
}  
  
// 实现Error trait
impl Error for MyCustomError {}

// 实现Display trait
impl fmt::Display for MyCustomError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.desc)
    }
}

fn process() -> Result<(), MyCustomError> {
    Err(MyCustomError {
        desc: "something is wrong".to_string(),
    })
}

fn main() {
    match process() {
        Ok(()) => println!("success"),
        Err(e) => {
            println!("failed: {}", e);
        }  
    }
}

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

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

相关文章

有没有好的视频素材网站官网?高清无水印素材下载

在这个数字化的时代&#xff0c;找到优质的素材对于创作者来说就像寻找一片绿洲一样重要。无论是个人项目还是专业作品&#xff0c;好的素材能够为作品增色不少。以下是我精选的一些素材网站&#xff0c;它们各具特色&#xff0c;提供从图片、视频到音效等多种素材&#xff0c;…

蓝桥杯练习03个人博客

个人博客 介绍 很多人都有自己的博客&#xff0c;在博客上面用自己的方式去书写文章&#xff0c;用来记录生活&#xff0c;分享技术等。下面是蓝桥云课的博客&#xff0c;但是上面还缺少一些样式&#xff0c;需要大家去完善。 准备 开始答题前&#xff0c;需要先打开本题的…

springboot284基于HTML5的问卷调查系统的设计与实现

问卷调查系统的设计与实现 摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;问卷信息因为其管理内容繁杂&#xff0c;管理数量繁多导…

2024年3月23日(星期六)骑行陡普鲁

2024年3月23日 (星期六&#xff09;骑行陡普鲁(春漫西翥千亩梨花节&#xff09;&#xff0c;早8:30到9:00&#xff0c;昆明氧气厂门口&#xff0c;9:30准时出发【因迟到者&#xff0c;骑行速度快者&#xff0c;可自行追赶偶遇。】 偶遇地点:昆明氧气厂门口集合 &#xff0c;家…

MySQL 多表关系(介绍) 一对多/多对多

一对多 举例介绍 例子: 部门与员工 在常理上来说: 一个部门有多个员工&#xff0c;一个员工只对应一个部门实现方式: 在多的一方建立外键&#xff0c;指向一的一方的主键 多对多 举例介绍 例子: 学生与课程 在常理上来说: 一个学生可以有多个课程,一门课程可以有多个学生实…

ideaSSM 工程车辆人员管理系统bootstrap开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 idea 开发 SSM 工程车辆人员管理系统是一套完善的信息管理系统&#xff0c;结合SSM框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具 有完整的源代码和数据库&…

10:00面试,10:06就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

Docker之大鲸鱼

什么是Docker&#xff1f; Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。 Docker常见命令&#xff1f; docker run -d \--name mys…

qt5-入门-国际化

参考&#xff1a; Qt 国际化(上)_w3cschool https://www.w3cschool.cn/learnroadqt/fwkx1j4j.html QT5实现语言国际化&#xff08;中英文界面动态切换&#xff0c;超详细&#xff09;_qt qevent::languagechange-CSDN博客 https://blog.csdn.net/m0_49047167/article/details/…

fs方法举例

fs.readFile() 读取文件 const fs require(node:fs) const path require(node:path) const s path.resolve(__dirname, ./hello.txt) const buf fs.readFileSync(s) console.log(buf.toString())输出的Buffer对象 用toString()方法转字符串之后 fs.appendFile() 创建新…

[视觉基础知识]: img to bev # include bev seg

参考&#xff1a;https://towardsdatascience.com/monocular-birds-eye-view-semantic-segmentation-for-autonomous-driving-ee2f771afb59 有源传感器&#xff08;lidar or radar&#xff09;得到的数据&#xff0c;天然就是一种bev表示&#xff08;x-y平面&#xff09;&#…

伊理威科技:抖音店铺运营好做吗

在数字营销的浪潮中&#xff0c;抖音以其强大的用户基础和独特的算法推荐机制成为了众多商家眼中的“香饽饽”。然而&#xff0c;对于许多初涉此领域的商家来说&#xff0c;心中不免有这样的疑问&#xff1a;“抖音店铺运营好做吗?” 运营一个抖音店铺并非易事。它既需要创意的…

一次完整的 HTTP 请求所经历的步骤

1&#xff1a; DNS 解析(通过访问的域名找出其 IP 地址&#xff0c;递归搜索)。 2&#xff1a; HTTP 请求&#xff0c;当输入一个请求时&#xff0c;建立一个 Socket 连接发起 TCP的 3 次握手。如果是 HTTPS 请求&#xff0c;会略微有不同。 3&#xff1a; 客户端向服务器发…

深入理解Sora技术原理

OpenAI 发布的视频生成模型 Sora(https://openai.com/sora)&#xff0c;能根据文本生成长达一分钟的高质量视频&#xff0c;理论上支持任意分辨率&#xff0c;如 1920x1080 、1080x1920 &#xff0c;生成能力远超此前只能生成 25 帧 576x1024 图像的顶尖视频生成模型 Stable Vi…

OSPF-1类Router LSA学习

前面我们又复习了一遍OSPF概述&#xff0c;在OSPF建立关系后有几种交互报文&#xff0c;通过LSU类型报文包含LSA信息实现路由信息传递&#xff0c;常见了1、2、3、4、5、7类LSA&#xff0c;分别对应不同功能使用。这里先看下1类LSA-Router LSA。 一、LSA概述 LSA&#xff0c;全…

蓝桥练习题总结(一)字母图形、完美的代价、01串、序列求和

目录 一、字母图形 二、完美的代价 三、01字串 四、序列求和 一、字母图形 问题描述 利用字母可以组成一些美丽的图形&#xff0c;下面给出了一个例子&#xff1a; ABCDEFG BABCDEF CBABCDE DCBABCD EDCBABC 这是一个5行7列的图形&#xff0c;请找出这个图形的规律&#xff…

慧海科创再探潮间带|全面调研推动梭子蟹产业进步

浙江的海岸线延绵,孕育了丰富的海洋生物多样性。在这样的背景下,慧海科创团队沿着宁波至舟山的潮间带开展了全面的调研活动。2024年3月15日,浙江海洋大学、宁波大学、上海理工大学的梭子蟹智能捆扎实践团队,深入海岸一线,与当地养殖户交流产业发展中的痛点难点,共同探讨梭子蟹产…

【云呐】固定资产管理系统有哪些主要功能

固定资产管理是一项非常重要的任务。许多企业选择固定资产管理系统&#xff0c;以提高运营效率&#xff0c;降低企业成本。那么&#xff0c;固定资产管理系统的关键功能是什么呢&#xff1f;这个功能如何实现企业高效管理&#xff1f;  固定资产管理系统最重要的作用是资产登…

铸铁平台制造工艺有多精细你知道吗——河北北重

铸铁平台的制造工艺要求相对较高&#xff0c;需要经过以下精细工艺&#xff1a; 材料选择&#xff1a;铸铁平台通常使用灰口铸铁&#xff0c;其具有良好的耐磨性和强度。材料的选择要考虑到使用环境和平台的功能需求。 模具制造&#xff1a;根据设计要求制作模具&#xff0c;模…

SinoDB客户端工具dbaccess

类似Oracle的客户端工具sqlplus&#xff0c;Mysql的客户端工具mysql&#xff0c;SinoDB数据库也有自带的命令行客户端工具dbaccess。 dbaccess 识别用户输入&#xff0c;将用户输入的 SQL 语句打包发送给 SinoDB 数据库服务器执行&#xff0c;然后接收服务器的执行结果&#xf…