Rust编程-错误处理

错误分类:

        可恢复错误:Result<T,E>。文件查找不存在,可以重试。

        不可恢复错误:panic!()宏。访问数组越界,会发生panic

不可恢复错误:

       

        处理方式:

                栈展开:Rust会沿着调用栈的反向顺序遍历所有调用函数,并依次清理这些函数中的数据。

                立即终止:直接结束程序且不进行任何清理工作,程序所使用过的内存只能由操作系统来进行回收。

                                Cargo.toml文件中添加配置:

[profile.release]
panic = 'abort'

                                在最终生成包里会采用立即终止程序

        获取回溯信息:

                回溯信息可能包含Rust核心库、标准库和第三方库

                RUST_BACKTRACE=1 cargo run

可恢复的错误:

        

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

        T代表了Ok变体中包含的值类型;E则代表了Err变体中包含的错误类型

         Result枚举及其变体已经通过预导入模块被自动地引入当前作用域中

         可以根据不同的错误原因,做出不同的处理:

                

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

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

    let f = match f {
        Ok(file) => file,
        Err(error) => match error.kind() { // error.kind() 返回的是枚举类型;该枚举类型需要引入标准库的ErrorKind
            ErrorKind::NotFound => match File::create("hello.txt") {
                Ok(fc) => fc,
                Err(e) => panic!("Tried to create file but there was a problem: {:?}", e),
            },
            other_error => panic!("There was a problem opening the file: {:?}", other_error), // 这里使用了other_error,表示不再穷举,对剩余的情况的统一处理
        },
    };

File::open返回的Err变体中的错误值类型,是定义在某个标准库中的结构体类型:io::Error。这个结构体拥有一个被称作kind的方法,调用它来获得io::ErrorKind值。 

 ErrorKind枚举:

enum ErrorKind {
    NotFound,
    PermissionDenied,
    DiskFull,
}

 利用闭包简化match嵌套:

let f = File::open("hello.txt").map_err(|error| { // 这里调用map_err()函数,里面是闭包函数
    if error.kind() == ErrorKind::NotFound {
        File::create("hello.txt").unwrap_or_else(|error| { // 这里调用unwrap_or_else()函数,里面是闭包
            panic!("Tried to create file but there was a problem: {:?}", error);
        })
    } else {
        panic!("There was a problem opening the file: {:?}", error);
    }
});

  这里使用了两个函数map_err()和unwrap_or_else():

        map_err(): 

                map_err 方法用于将错误类型从一个类型转换为另一个类型。它接收一个闭包(closure),该闭包将原始错误类型转换为新的错误类型。map_err 通常用于在错误处理链中将错误类型统一化,以便更方便地处理错误。

                代码中error.kind() 将io::Error转换成io::ErrorKind, 然后进行比较。

                

use std::fs::File;
use std::io::Error;

let file = File::open("non_existent_file.txt").map_err(|err| {
    Error::new(err.kind(), "文件不存在")
});

使用 map_err 将 io::Error 转换为自定义的 Error 类型。 

        unwrap_or_else():

    unwrap_or_else 方法用于处理 Option 或 Result 类型的值。如果值是 Some 或 Ok,则返回其中的值;否则,执行提供的闭包,并返回闭包的返回值。

let value = Some(42);
let result = value.unwrap_or_else(|| 0); // 成功返回42,失败返回0
println!("result: {}", result); // 输出:result: 42

let none_value: Option<i32> = None;
let result = none_value.unwrap_or_else(|| 0); 
println!("result: {}", result); // 输出:result: 0

        快速触发panic的两个方法:(中断程序继续运行

                unwrap(): 当Result的返回值是Ok变体时,unwrap就会返回Ok内部的值。而当Result的返回值是Err变体时,unwrap则会替我们调用panic! 宏

                expect(): 基于unwrap函数,expect("xxx") 可以传入参数,表明错误的具体原因

错误传播:return or ?

        

fn read_username_from_file() -> Result<String, io::Error> {
    let f = File::open("hello.txt");
    let mut f = match f {
        Ok(file) => file,
        Err(e) => return Err(e), // 通过return返回Err(e) ,将错误返回给调用者
    };
    let mut s = String::new();
    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(e) => Err(e), // 返回Err,返回给调用者。由于这里是函数的最后一个表达式,所以我们不再需要显式地添加return。
    }
}
        ?运算符:

                传播错误的模式在Rust编程中非常常见,所以Rust专门提供了一个问号运算符(?)来简化它的语法。

                将?放置于Result值。假如这个Result的值是Ok,那么包含在Ok中的值就会作为这个表达式的结果返回并继续执行程序。假如值是Err,那么这个值就会作为整个程序的结果返回,如同使用了return一样将错误传播给调用者。

              使用了?运算符的函数必须返回Result、Option或任何实现了std::ops::Try的类型

fn read_username_from_file() -> Result<String, io::Error> { // 返回类型是Result<String,io::Error>
    let mut s = String::new();

    File::open("hello.txt")?.read_to_string(&mut s)?; //这里是加分号

    Ok(s)
}

错误类型:

        std::io::Error: 表示I/O错误的类型。它包含一个ErrorKind和一个可选的错误消息,用于表示I/O操作过程中的错误,例如文件I/O,网络I/O或其他类型的I/O。

        std::io::ErrorKind: 它是一个枚举,表示I/O错误的类型。它的枚举变体有NotFound,PermissionDenied,ConnectionRefused和其他类型。ErrorKind用于对I/O错误的类型进行分类,使其更容易处理和响应不同类型的错误。

        std::error::Error: 表示一个泛型的错误类型的trait。它提供一种将错误类型转换为字符串的方法,从而可以向用户显示错误消息。Error是io::Error的超trait。意味着,上线了io::Error也实现了Error。

        

use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> { // 允许将错误转换成字符串显示给用户
    let file = File::open("non_existent_file.txt")?;
    Ok(())
}

何时panic!:

        代码一旦发生panic,就再也没有恢复的可能了.

        返回一个Result值时,你就将这种选择权交给了调用者

        通过人工检查确保代码永远不会出现Err变体,那就使用unwrap。unwrap内部是调用panic!()宏。

        某个错误可能会导致代码处于损坏状态时,使用panic来处理错误。损坏状态意味着设计中的一些假设、保证、约定或不可变性出现了被打破的情形。比如,当某些非法的值、自相矛盾的值或不存在的值被传入代码中

        假如错误是可预期的,那么就应该返回一个Result而不是调用panic!

        

  • 26
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值