[Rust Guide] Classification and Delivery of Errors | Exception Handling with Kind

insert image description here

  foreword

  Rust has a unique mechanism for handling exceptions, which is not as simple as the try mechanism in other languages.
Errors in Rust fall into two broad categories: recoverable errors and unrecoverable errors. Most programming languages ​​use Exception(exception) classes to represent errors. There are no Exceptions in Rust. Use the Result<T, E>class and panic!macros for unrecoverable errors.


1. Unrecoverable error

  • Caused by a logical error that cannot be resolved in programming, such as accessing a location other than the end of an array .

1.1. Use of panic! macro

The use of macros is relatively simple, let's look at a concrete example:

fn main() {
    
    
    panic!("Error occured");
    println!("Hello, rust");
}

operation result:

insert image description here

Obviously, the program does not run as expected println!("Hello, rust"), but stops running when the panic!macro is called. Unrecoverable errors will definitely cause the program to be fatally hit and terminate.

1.2. Analyze the cause of the error through the Powershell command line

Let's analyze the error message in the terminal command line:

thread 'main' panicked at 'Error occured', src\main.rs:2:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
  • The first line outputs the location of the panic! macro call and the error message it outputs
  • The second line is a prompt, translated into Chinese is " run through the RUST_BACKTRACE=fullenvironment variable to display the traceback ". Next look at the traceback ( backtrace) information:
stack backtrace:
   0: std::panicking::begin_panic_handler
             at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library\std\src\panicking.rs:584
   1: core::panicking::panic_fmt
             at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library\core\src\panicking.rs:142
   2: error_deal::main
             at .\src\main.rs:2
   3: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
             at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3\library\core\src\ops\function.rs:248

Backtracking is another way of dealing with unrecoverable errors, it unwinds the running stack and outputs all the information, and the program still exits. Through a lot of output information, we can find the error triggered by the panic! macro we wrote.

2. Recoverable errors

  • If accessing a file fails, it may be because it is being occupied, which is normal, and we can solve it by waiting .

2.1, the use of Rustlt<T, E> enumeration classes

This concept is very similar to the exception in the Java programming language. In the C language, we often set the function return value as an integer to express the error encountered by the function. In Rust, the Result<T, E> enumeration class is used as the return value to express the exception:

enum Result<T, E> {
    
    
    Ok(T),
    Err(E),
}//T的类型不定,相当于C++中模板的写法

We know that it enumis often used in matchconjunction with, and when a match is found OK, the corresponding code will be executed.

The return values ​​of functions in the Rust standard library that can generate exceptions are all of Resulttype .

For example: when we try to open a file:

use std::fs::File;

fn main() {
    
    
    let fp = File::open("hello_rust.txt");
    match fp {
    
    
        Ok(file) => {
    
    
            println!("File opened successfully.");
        },
        Err(err) => {
    
    
            println!("Failed to open the file.");
        }
    }
}//OK里的参数file是File类型,相当于填充了枚举里的T类型

If the hello_rust.txtfile does not exist, Failed to open the file will be printed.

Of course, the if letpattern can simplify the matchsyntax block:

use std::fs::File;

fn main() {
    
    
    let fp = File::open("hello_rust.txt");
    if let Ok(file) = fp {
    
    
        println!("File opened successfully.");
    } else {
    
    
        println!("Failed to open the file.");
    }
}

2.2, the unwrap() and expect(message: &str) methods of the Result class

  • Treat a recoverable error as an unrecoverable error

for example:

use std::fs::File;

fn main() {
    
    
    let fp1 = File::open("hello_rust.txt").unwrap();
    let fp2 = File::open("hello_rust.txt").expect("Failed to open.");
}
  • This program is equivalent to calling the panic! macro Errwhen .
  • The difference between the two is the expectability to send a specified error message to the panic! macro
  • panic!macro is an unrecoverable error, this completes the transition

3. Recoverable error delivery

What I talked about before is the processing method of receiving an error. Next, I will talk about how to pass the error information out.

Let's start by writing a function:

fn f(i: i32) -> Result<i32, bool> {
    
    
    if i >= 0 {
    
    
         Ok(i) 
        }
    else {
    
     
        Err(false) 
    }
}
fn main() {
    
    
    let r = f(10000);
    if let Ok(v) = r {
    
    
        println!("Ok: f(-1) = {}", v);
    } else {
    
    
        println!("Err");
    }
}//运行结果:Ok: f(-1) = 10000

rThe result here is freturned by the function ok(10000), and the value after if letpattern matching vis 10000

The function in this program fis the source of the error, now let's write another function that passes the error g:

fn g(i: i32) -> Result<i32, bool> {
    
    
    let t = f(i);
    return match t {
    
    
        Ok(i) => Ok(i),
        Err(b) => Err(b)
    };
}

The function g passes the possible errors of the function f, which is a bit verbose. In Rust, you can add the ?operator Errto pass the same type directly:

fn f(i: i32) -> Result<i32, bool> {
    
    
    if i >= 0 {
    
     Ok(i) }
    else {
    
     Err(false) }
}

fn g(i: i32) -> Result<i32, bool> {
    
    
    let t = f(i)?;
    Ok(t) // 因为确定 t 不是 Err, t 在这里已经推导出是 i32 类型
}

fn main() {
    
    
    let r = g(10000);
    if let Ok(v) = r {
    
    
        println!("Ok: g(10000) = {}", v);
    } else {
    
    
        println!("Err");
    }
}//运行结果:Ok: g(10000) = 10000

?The actual function of the operator is to directly take out the non-abnormal value of the Result class, and return the abnormal Result if there is an exception. Therefore, the ? operator is only used for functions whose return value type is Result<T, E>, and the Etype must be ?the same as the E type of the Result being processed.

4. Handle exceptions with the kind method

Although it was mentioned earlier that exceptions in Rust are not as simple as other languages, that doesn't mean that Rust can't do it: we could implement the tryblock in a separate function and pass all the exceptions out for resolution.

This is actually the way a well-differentiated program should be programmed: it should focus on the integrity of individual functions.

But this needs to judge the Err type of Result, the function to get the Err type iskind()

Make an instance of opening a file:

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

fn read_text_from_file(path: &str) -> Result<String, io::Error> {
    
    
    let mut f = File::open(path)?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

fn main() {
    
    
    let str_file = read_text_from_file("hello_rust.txt");
    match str_file {
    
    
        Ok(s) => println!("{}", s),
        Err(e) => {
    
    
            match e.kind() {
    
    
                io::ErrorKind::NotFound => {
    
    
                    println!("No such file");
                },
                _ => {
    
    
                    println!("Cannot read the file");
                }
            }
        }
    }
}//这里我没有创建hello_rust.txt文件,因此运行结果为:No such file

Code Explanation:

  • Using a read_text_from_file()function to pass the result of opening a file to a str_filevariable

    • It does not exist here hello_rust.txt, so File::open(path)?the file will not be opened, and the exception will be stored fin
    • f.read_to_string(&mut s)?Can't read the file content, ok(s)no content
  • Through analysis, the branch will execute Err(e)the code block, use e.kind()the error type and matchbranch again

    • If it is NotFoundan error, it will print No such file
    • Other errors are prompted Cannot read the file

Rust 的错误处理到此分享结束,欢迎大家指点,如有不恰当的地方还请不吝提出,让我们在交流中进步!

Guess you like

Origin blog.csdn.net/m0_58618795/article/details/127034383