当前位置: 首页 > article >正文

【Rust中的错误处理】

Rust中的错误处理

  • 什么是错误处理
  • Rust中的错误处理
  • 比Result<T,E>更强硬的panic!
  • 比单独调用panic更丝滑的unwrap,expect:
  • 总结


什么是错误处理

‌错误处理‌是指在编程过程中,对程序运行时出现的错误进行检测、捕获和处理的过程,以确保程序能够按照预期正常运行。
对于程序来说,一般可将错误分解为两大类,一类是因外部输入或调用方式有问题而产生的错误,一类是程序编写出现的错误问题,前者多半不会给程序带来极端的问题,而后者很有可能造成程序的崩溃等,所以编程时需要进行正确地错误处理。
C++/C#均有各自的错误处理方法,有各自的error库,并有异常处理机制,不过这都需要人为“注意”,也就是说如果你忽略了错误处理,其编译器并不会提示你这是有问题的。

Rust中的错误处理

Rust在代码规则中便支持在需要错误处理的地方,如返回值使用Result<T,E>,或者在必要时Panic!
这两个方式便可以当作一种是软处理,一种时强硬的处理方式。(Result<T,E> 会在发生错误时将错误向上抛出,Panic!则会在发生错误的时候将程序运行的线程干掉,所以这也是为什么我们鼓励不要再主线程中做太多的事情。)

代码示例:

use std::fs::File;
use std::io::{Error, Read};

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

fn main() {
    let content = read_file("example.txt");
    match content {
        Ok(content) => println!("文件内容: {}", content),
        Err(error) => println!("发生错误: {:?}", error),
    }
}

上述代码返回值 Result<String, Error> 是一个enum,它包含了两种返回结果Ok和Error,Ok即文件读取成功,Error即失败,返回特定的error,而正确地返回值只有一个就是Ok(contents)。
在函数中,我们看到有两个【?;】为结尾的行,其 表示当错误发生时,程序便会从【?】位置将问题抛转到调用方处理

file.read_to_string(&mut contents)?//最后一行这样写可不可以?

不可以,【?】只是错误处理的语法糖,不是返回值的语法糖,也就是说你只能够在错误发生时的值而没有办法返回成功时候的OK(xxx)。

比Result<T,E>更强硬的panic!

panic多用于无法接受的程序错误,拿着一个极端错误的结果往下走逻辑时没有必要的,甚至会徒增排查问题的难度时。
代码示例:

//数组访问越界时会被动触发panic
let v = vec![1,2,3];
println!("{:?}",v[3]);
//主动调用,下面这段代码是没有意义的,只是为了展示主动调用
fn main() {
    panic!("boom");
}

比单独调用panic更丝滑的unwrap,expect:

unwrap当返回值正常时与Ok(xxx) or Some(xxx)无异,而当程序有异常时则直接panic线程。
代码示例:

use std::net::IpAddr;
fn main() {
    let _ = func();
}
fn func() -> Result<IpAddr, Box<dyn std::error::Error>> {
    Ok("1271".parse().unwrap())
}

很明显,以上“1271”无法转换成ip地址,此段程序将直接panic!,以下是错误输出:

thread 'main' panicked at main.rs:7:23:
called `Result::unwrap()` on an `Err` value: AddrParseError(Ip)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

根据提示开发者可以根据栈展开深入查看问题的原因。
expect代码示例:

use std::net::IpAddr;
fn main() {
    let _ = func();
} //-
fn func() -> Result<IpAddr, Box<dyn std::error::Error>> {
    //+
    Ok("1271".parse().expect("cannote parse str to ipaddr")) //+
}

输出:
thread ‘main’ panicked at main.rs:7:23:
cannote parse str to ipaddr: AddrParseError(Ip)
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace

多了一些问题标注信息

让我们展开看一下unwrap源码:

    #[inline(always)]
    #[track_caller]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn unwrap(self) -> T
    where
        E: fmt::Debug,
    {
        match self {
            Ok(t) => t,
            Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e),
        }
    }
-------------------------------------------------------------------------------------------
#[cfg(not(feature = "panic_immediate_abort"))]
#[inline(never)]
#[cold]
#[track_caller]
fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! {
    panic!("{msg}: {error:?}")
}

显而易见的,unwrap内部在unwrap_failed 调用了panic。expect亦是如此。


总结

当然在实际工程开发中我们有狠多crate可以选择,而不是简单的直接裸使用这些Error处理,通过anyhow,thisError加上tracing这样优秀的问题跟踪crate,使得我们的代码更加的具备鲁棒性,也更易于发现问题并即使解决问题。

如有勘误,敬请指出。


http://www.kler.cn/a/380334.html

相关文章:

  • 论文阅读-用于点云分析的自组织网络
  • 【初阶数据结构与算法】复杂度分析练习之轮转数组(多种方法)
  • React第十三章(useTransition)
  • 每日一言 动态图片
  • 「Mac畅玩鸿蒙与硬件28」UI互动应用篇5 - 滑动选择器实现
  • 初始JavaEE篇——多线程(5):生产者-消费者模型、阻塞队列
  • (十二)JavaWeb后端开发——MySQL数据库
  • SpringBoot框架:新闻稿件管理技术进阶
  • Redis数据类型——针对实习面试
  • 绿宝石二十载:如何打破国外在高端电容市场的垄断?
  • China Geodetic Coordinate System 2000 PRJ文件解析
  • java重要知识点 JVM基本结构
  • ACM模式输入输出处理(JS版)
  • ONLYOFFICE 文档8.2更新评测:PDF 协作编辑、性能优化及更多新功能体验
  • ChatGPT中的RAG;大模型微调;通过正确的提问和回答数据进行问答系统的微调;
  • YOLOv10的网络架构解析
  • 全面解析:容器化技术及其应用
  • Spring框架的JDBC模板技术
  • Python绘制爱心
  • 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-29
  • 前端面试题22 | 什么是跨域问题?怎么解决?
  • java 对人名和电话 脱敏-replaceAll
  • HTB:Mirai[WriteUP]
  • 第七部分:1. STM32之ADC实验--单通道实验
  • 新世联科技:NG2-A-7在DAC空气捕集提取CO2的应用
  • Ps:天空替换