首页 > 其他分享 >rust学习十、异常处理(错误处理)

rust学习十、异常处理(错误处理)

时间:2024-11-19 18:18:45浏览次数:1  
标签:username std use file let File 错误处理 异常 rust

在书籍中,中文译者翻译为错误,这是因为原文是"Error"。

但在很多语言中,都是书写为异常。

一、概述

rust的错误处理与众不同,前文已经提及:大家称为异常,它称为错误。

 

不可恢复的错误,可以大体称为panic(恐慌)! 太率性了....

那么我们的问题是:除了一些的确不可处理的异常,rust是否也和大部分语言那样使用try catch来捕获和跳过?

所谓的不可恢复错误,其实也可以被try catch处理?

 

二、用panic!宏处理错误

不可恢复错误发生的时候的通常表现:会打印出一个错误信息,展开并清理栈数据,然后退出

通过一个环境变量,可以让 Rust 在 panic 发生时打印调用堆栈(call stack)以便于定位 panic 的原因.

 

两种退出方式

  1. abort- 粗暴退出,让操作系统收拾残局
  2. 回溯栈并清理它遇到的每一个函数的数据。如果需要查看堆栈,可以把环境变量RUST_BACKTRACE设置为不是0即可

设置退出方式

Cargo.toml中设置,如下:

[profile.release]
panic = 'abort'

上文中,panic还可以是设置为unwind,这是默认的

上例是release,如果想在调试的时候,那么可以添加profile.dev

更多的配置,可以参考 https://www.rustwiki.org.cn/zh-CN/cargo/index.html

 

触发方式

  1. 直接调用panic!宏
  2. 一些可能导致不可恢复的错误,例如除以0,越绝访问向量

 

示例一、直接触发

 输出一大堆!!!

示例二、越界访问

输出太多,截取了比较又意义的部分:已经足够明白那里发生错误的。

毫无疑问,对于第二种情况,在其它语言种,一般简单try catch就可以处理了!

三、用Result处理可恢复错误

Resutt<T,E>是什么

一个枚举类型,类似Option。

有两个成员Ok,Err

和Option的Some,None一样,Ok,Err也是可以直接使用,不需要书写前缀,因为它们都在prelude中导入了。

注意:prelude是序章的意思,可以理解为rust为每一个应用自动导入的部分。

 

处理Result,处理错误类型

由于Result是Option,所以,可以这样使用:

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

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

    let greeting_file = match greeting_file_result {
        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:?}");
            }
        },
    };
}

 

或者

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

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

 

失败的两种处理:unwrap,expect

use std::fs::File;

fn main() {
    let greeting_file = File::open("hello.txt").unwrap();
    let greeting_file2 = File::open("hello.txt")
        .expect("hello.txt should be included in this project");
}

unwrap和expect的区别在于:后者会在触发错误的时候,直接打印参数值。

expect方法内部大体是这样的:

    #[inline]
    #[track_caller]
    #[stable(feature = "result_expect", since = "1.4.0")]
    pub fn expect(self, msg: &str) -> T
    where
        E: fmt::Debug,
    {
        match self {
            Ok(t) => t,
            Err(e) => unwrap_failed(msg, &e),
        }
    }

 

逻辑:正常就返回值、不正常的则返回一个异常(不可恢复的错误,退出)。

 

3.1传播错误-如何处理错误

在大部分的语言中,有两种方式:继续抛出或者捕获之后做其它处理,例如java就是这样处理的。

这个内容比较多,所以单独一个小章节说明:

  1. 常规处理-根据result结果返回需要的内容
  2. 使用?简化处理
  3. 不是任何地方都可以用?
  4. 让main()函数可以支持?
  5. Box<dyn Error>

常规处理-这个没有什么好说的。

使用?简化处理

 

1.正常代码

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

fn read_username_from_file() -> Result<String, io::Error> {
    let username_file_result = File::open("hello.txt");

    let mut username_file = match username_file_result {
        Ok(file) => file,
        Err(e) => return Err(e),
    };

    let mut username = String::new();

    match username_file.read_to_string(&mut username) {
        Ok(_) => Ok(username),
        Err(e) => Err(e),
    }
}

 

 

2.简化代码-1

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

fn read_username_from_file() -> Result<String, io::Error> {
    let mut username_file = File::open("hello.txt")?;
    let mut username = String::new();
    username_file.read_to_string(&mut username)?;
    Ok(username)
}

 

?这里表示 match xxxx 一段内容。如果出现异常,已经退出了。

 

3. 继续简化的代码_2

use std::fs::File;
use std::io::{self, Read};
fn read_username_from_file() -> Result<String, io::Error> {
    let mut username = String::new();
    File::open("hello.txt")?.read_to_string(&mut username)?;
    Ok(username)
}

 

这里主要使用链式写法简化了。毫无疑问,这个链式的还是比较受到欢迎的!!!

 

哪里不能用?

函数的返回值不同于?

最典型例子:

use std::fs::File;

fn main() {
    let greeting_file = File::open("hello.txt")?;
}

 

这是因为main的返回类型是()    --  rust的什么都奇怪的很,虽然最内核大家都差不多。

让main支持?

有什么惊人之举吗?没有,就是修改返回类型。

use std::error::Error;
use std::fs::File;

fn main() -> Result<(), Box<dyn Error>> {
    let greeting_file = File::open("hello.txt")?;

    Ok(())
}

 

四、要不要panic!宏

 原文说了一堆口水话,对于有经验的工程师而言,没有什么价值。略!

五、小结

  1. rust的错误处理和其它部分一样,力图做到与众不同- Error,panic!、Ok、Err、?、Box 这是凭空多出来的一些新概念(老东西换新的名称)
  2. 暂时没有介绍如何让所谓的不可恢复错误编程可以忽略的异常 --类似越界访问,在其它语言再正常不过了
  3. 利用Resut和?某种程度上,会让代码看起来比一些语言好看一些(仅仅是好看而已)
  4. 注意异常处理原则。 或者注意团队中的统一处理原则
  5. 一个最重要的内容本章并没有提到:发生致命错误的时候,如何避免退出。这种要求十分常见,例如越界访问。但这个应该是一定有的,只是本章并没有提到。

 

标签:username,std,use,file,let,File,错误处理,异常,rust
From: https://www.cnblogs.com/lzfhope/p/18553226

相关文章

  • Konsole 中文字体异常显示 ,粗细不一致
    写入~/.config/fontconfig/fonts.conf,确定你安装了其中的字体<?xmlversion='1.0'?><!DOCTYPEfontconfigSYSTEM'fonts.dtd'><fontconfig><!--默认字体设置--><matchtarget="pattern"><testqual="any&qu......
  • quartz .net8微服务避免dbcontext异常示例
     调整program.cs里注册QuartzJobService,去除掉原有框架内的QuartzCore文件夹中的Factorymiddlejob等方法//注册QuartzJobServicebuilder.Services.AddQuartz(q=>{varjobKey=newJobKey("Jobs");q.AddJob<InterAutoTicketing>(opts=>opts.WithIdentity(j......
  • Rust impl关键字(实现封装、继承和多态等功能)(Rust关联类型、impl关联类型、Rust静态方
    文章目录Rust中的`impl`关键字详解什么是`impl`关键字?`impl`的基本语法示例:为结构体实现方法`impl`与特征(Trait)(为类型实现通用接口)示例:为类型实现特征`impl`与关联类型(关联类型使得在特征中定义的一些类型可以在实现时具体化)示例:使用关联类型`impl`与静态方法(不带self......
  • rust学习九.3-集合之哈希映射表
    这里介绍的哈希映射表(HashMap)并非是java那样的万用表,限制很大。不过,话说回来,rust应该是有类似java那样的映射表,不过不是这个哈希映射表。现在先谈论哈希映射表吧。 一、构成和定义HashMap是最不常用的,所以并没有被prelude自动引用。标准库中对HashMap的支持也相对较少......
  • rust学习九.2、集合之字符
    按照作者的意思,字符不是看起来那么简单!的确,字符在大部分语言中,都不是看起来那么简单!字符的内容看起来很多,又很少!多是因为涉及到编码、构成、方法(有许多方法)还有字符切片。少是因为,其实和java等语言其实没有大的区别。一、构成rust的字符内部是vec(u8)+方法,看起来和java其实......
  • Mybatis 常见异常
    Mybatis列表查询只返回了部分数据,Sql语句多出limit异常//list查询接口List<Info>infoList=xxxMapper.selectList();列表查询接口,只返回了部分数据原因通过日志观察,发现日志打印的sql多了limit参数,怀疑时与分页有关;基于此,搜索资料发现,PageHelper插件是通过ThreadLoc......
  • 24.Python基础篇-异常处理
    1.什么是异常?异常(Exception)是程序在运行过程中出现的错误情况。Python提供了强大的异常处理机制,使得程序在遇到错误时能够继续执行或者给出适当的错误提示。避免程序因为某个错误而中断。异常处理有助于提高代码的健壮性,2.异常处理的语法:try:用于包围可能会抛出异常的代码块......
  • 异常值检测:SOS算法(Stochastic Outlier Selection Algorithm)MATLAB代码
    SOS算法(StochasticOutlierSelectionAlgorithm)是由JeroenJanssens提出的一种无监督异常检测算法。该算法通过计算数据点之间的关联度(affinity)来识别异常点。核心思想是,如果一个点与其他所有点的关联度都很低,那么它被视为异常点。以下是该算法的详细公式和步骤:其MATLAB代码......
  • 8、异常向量表的安装与调用
    1.回顾中断的发生、处理过程中断发生的硬件过程中断处理的软件处理流程CPU执行完当前指令,检查到发生了中断,跳到向量表保存现场、执行GIC提供的处理函数、恢复现场2.异常向量表的安装2.1复制向量表汇编代码//arch\arm\kernel\head.S1.bl __lookup_pr......
  • go fiber: 把异常信息写到错误日志中
    一,代码:1,userBusiness.gopackagebusinessimport("fmt")//得到多个用户,按分页返回funcGetUserList(pageint,pageSizeint)(string,error){b:=0a:=100/bfmt.Println(a)return"1,2,3",nil}代码中包含有除0错,会引发panic2,userControlle......