Rust错误处理


在Rust中,错误可以分为两大类,如下表所示:

序号名称与说明用法
1

Recoverable

可以处理的错误

Result枚举
2

UnRecoverable

无法处理的错误

panic宏

可恢复的错误是可以纠正的错误。当程序遇到可恢复的错误时,它可以重试失败的操作或指定其他操作方案。可恢复的错误不会导致程序突然失败。可恢复错误的一个示例是 文件未找到 error.

不可恢复的错误导致程序突然失败。如果发生不可恢复的错误,程序将无法恢复到其正常状态。它无法重试失败的操作或撤消错误。不可访问错误的一个示例是尝试访问数组末尾以外的位置。

与其他编程语言不同,Rust没有例外。它返回一个枚举 结果

panic!宏和不可恢复的错误


panic!宏允许程序立即终止并向程序调用者提供反馈,当程序达到不可恢复的状态时,应使用它。

fn main() {
    panic!("Hello");
    println!("End of main"); //无法访问的语句
}

在上面的示例中,程序在遇到以下情况时将立即终止: panic! macro.

thread 'main' panicked at 'Hello', main.rs:3

例子:panic!宏

fn main() {
    let a = [10,20,30];
    a[10]; //由于无法到达索引10引起了恐慌
}

输出如下图:

warning: this expression will panic at run-time
--> main.rs可以处理的错误4
  |
4 | a[10];
  | ^^^^^ index out of bounds: the len is 3 but the index is 10

$main
thread 'main' panicked at 'index out of bounds: the len 
is 3 but the index is 10', main.rs:4
note: Run with `RUST_BACKTRACE=1` for a backtrace.

一个程序可以引起恐慌!违反业务规则的宏,如下例所示:

fn main() {
    let no = 13;
    //尝试使用奇数和偶数
    if no%2 == 0 {
        println!("Thank you , number is even");
    } else {
        panic!("NOT_AN_EVEN");
    }
    println!("End of main");
}

如果分配给变量的值是奇数,则上面的示例将返回错误。

thread 'main' panicked at 'NOT_AN_EVEN', main.rs:9
note: Run with `RUST_BACKTRACE=1` for a backtrace.

结果枚举和可恢复的错误


Result结果:

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

让我们借助示例了解这一点:

use std::fs::File;
fn main() {
    let f = File::open("main.jpg");
    //此文件不存在
    println!("{:?}",f);
}

程序返回 OK(File) 如果文件已经存在,并且 错误(错误) 如果找不到该文件。

Err(Error { repr: Os { code: 2, message: "No such file or directory" } })

现在让我们看看如何处理Err变体。

以下示例使用match语句处理使用打开文件时返回的错误:

use std::fs::File;
fn main() {
    let f = File::open("main.jpg");   // main.jpg不存在
    match f {
        Ok(f)=> {
            println!("file found {:?}",f);
        },
        Err(e)=> {
            println!("file not found \n{:?}",e);   //处理错误
        }
    }
    println!("end of main");
}

注意:程序打印 end of main ,但未找到文件。这意味着程序已正确处理了错误。

file not found
Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }
end of main

例子

is_even函数如果数字不是偶数,则函数将返回错误,main()函数处理此错误。

fn main(){
    let result = is_even(13);
    match result {
        Ok(d)=>{
            println!("no is even {}",d);
        },
        Err(msg)=>{
            println!("Error msg is {}",msg);
        }
    }
    println!("end of main");
}
fn is_even(no:i32)->Result<bool,String> {
    if no%2==0 {
        return Ok(true);
    } else {
        return Err("NOT_AN_EVEN".to_string());
    }
}

注意:由于主要功能可以正常处理错误,因此打印 end of main 。

Error msg is NOT_AN_EVEN
end of main

unwrap()和Expect()


标准库包含两个枚举的辅助方法:

序号
方法签名与说明
1unwrap

unwrap(self): T

期望self是Ok / Some并返回其中包含的值。如果是ErrorNone相反,它对显示的错误内容引起了恐慌。

2expect

expect(self, msg: &str): T

行为就像解包一样,除了它会在错误内容之前输出一个在恐慌之前的自定义消息。

unwrap()


unwrap()函数返回操作成功的实际结果。如果操作失败,它将返回带有默认错误消息的紧急消息。该函数是match语句的简写。在下面的示例中显示:

fn main(){
    let result = is_even(10).unwrap();
    println!("result is {}",result);
    println!("end of main");
}
fn is_even(no:i32)->Result<bool,String> {
    if no%2==0 {
        return Ok(true);
    } else {
        return Err("NOT_AN_EVEN".to_string());
    }
}
result is true
end of main

修改上面的代码以将奇数传递给is_even()函数

unwrap()函数将出现紧急情况并返回默认错误消息,如下所示

thread 'main' panicked at 'called `Result::unwrap()` on 
an `Err` value: "NOT_AN_EVEN"', libcore\result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace

expect()


如果出现紧急情况,程序可以返回自定义错误消息,在下面的示例中显示:

use std::fs::File;
fn main(){
    let f = File::open("pqr.txt").expect("File not able to open");
    // 文件不存在
    println!("end of main");
}

函数Expect()与unwrap()类似,唯一的区别是可以使用期望显示自定义错误消息。

thread 'main' panicked at 'File not able to open: Error { repr: Os 
{ code: 2, message: "No such file or directory" } }', src/libcore/result.rs:860
note: Run with `RUST_BACKTRACE=1` for a backtrace.