T rust error handling

Posted by yazz on Thu, 23 Sep 2021 08:14:15 +0200

Overview of t rust error handling

  • Reliability of t rust: error handling

    • In most cases: an error is prompted at compile time
  • Wrong classification

    • recoverable

      • For example, if the file is not found, try again
    • Unrecoverable

      • bug, for example, the index accessed is out of range
  • T rust has no exception like mechanism

    • Recoverable error, result < T, E >
    • Unrecoverable error, panic! macro

Unrecoverable error with panic!

  • When panic! Macro execution:

    • Your program will print an error message
    • Expand (unwind) and clean up the call stack
    • Exit program
  • By default, panic! happen:

    • Program expansion call stack (heavy workload)

      • Rust walked back along the call stack
      • Clean up the data in each encountered function
    • Or immediately terminate the call stack

      • Stop the program directly without cleaning
      • The memory needs to be cleaned up by the OS
  • To make the binary smaller, change the setting from expand to abort:

    • Set the appropriate profile section in Cargo.toml:
      • panic = 'abort'
[package]
	name = "demo"
	version = "0.1.0"
	authors = ""
	edition = "2018"
[dependencies]
[profile.release]
	panic = 'abort'

Backtracking information generated using panic

  • panic! May appear in:

    • In the code we write
    • In the code we rely on
  • You can locate the code causing the problem by calling the backtracking information of the function of panic

  • Backtrace information can be obtained by setting the environment variable RUST_BACKTRACE

  • In order to get backtracking with debug information, the debug symbol (without -- release) must be enabled

Result and recoverable error

Result enumeration

  • enum Result<T, E>{

    ​ Ok(T),

    ​ Err(E),

    }

    T: The data type returned in the Ok variant when the operation is successful

    E: Type of error returned in Err variant in case of operation failure

use::fs::File;
fn main(){
	let f = File::open("hello.txt");
}

One way to handle a Result: a match expression

use std::fs::File;

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

    let f = match f {
        Ok(file) => file,
        Err(error) => panic!("Problem opening the file: {:?}", error),
    };
}

Match different errors

use std::fs::File;
fn main(){
	let f = File::open("hello.txt");
    let f = match f{
    	Ok(file) => file,
        Err(error) => match error.kind(){
            ErrorKind::NotFind => match File::create("hello.txt"){
                Ok(fc) => fc,
                Err(e) => panic!("Error creating file:{:?}", e),
            },
            other_error => panic!("Error opening the file:{:?}", other_errpr),
        }
    };
}

Unwrap: a shortcut to match expressions:

  • If the Result is Ok, return the value in Ok

  • If the Result is Err, call the panic! Macro

use std::fs::File;
fn main(){
    let f = File::open("hello.txt").unwrap();
}

expect: similar to unwrap, but you can specify an error message

use std::fs::File;
fn main(){
	let f = File::open("hello.txt").expect("File does not exist!");
}

Propagation error

  • Processing error in function
  • Returns the error to the caller
use std::fs::File;
use std::io;
use std::io::read;
fn read_username_from_file() -> Result<String, io::err> {
	let f = File::open("hello.txt");
    let mut f = match f{
        Ok(file) => file,
        Err(e) => return Err(e),
    };
    let mut s = String::new();
    
    match f.read_to_string(&mut s){
        Ok(_) => Ok(s),
        Err(e) => Err(e),
    }
}

? operator

  • ? operator: a shortcut to propagate errors
  • If the Result is Ok: the value in Ok is the Result of the expression, and then continue to execute the program
  • If the Result is Err: Err is the return value of the whole function, just like using return
use std::fs::File;
use std::io;
use std::io::Read;
fn read_username_from_file() -> Result<String, io::Error> {
	let f = File::open("hello.txt")?;
  
    let mut s = String::new();
    
    f.read_to_string(&mut s)?;
    Ok(s)
}

? and from functions

  • From function on trail STD:: convert:: from:

    • Used for conversion between errors
  • When an error is applied, it will be implicitly handled by the from function

  • When? Calls the from function:

    • The error type it receives is converted to the error type defined by the return type of the current function

      EA - > EB, EA implements the from function, and the return value is EB

  • Used to return the same error type for different error causes

    • As long as each error type implements the from function converted to the returned error type

call chaining

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

The? Operator can only be used for functions with a return value of Result

? operator and main function

  • The return type of the main function is: ()
  • The return type of the main function can also be: result < T, E >
  • Box is a trait object:
    • Simple understanding: "any possible error type"

When to use panic!

General principles

  • When defining a function that may fail, give priority to returning Result
  • Otherwise, return panic!

Topics: Rust