Rust编程语言-9-异常处理

异常处理

panic!宏处理不可恢复的异常,程序终止

fn main() {
    let v = vec![1, 2, 3];
    v[99];
}

$ cargo run
   Compiling panic v0.1.0 (file:///projects/panic)
    Finished dev [unoptimized + debuginfo] target(s) in 0.27s
     Running `target/debug/panic`
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', src/main.rs:4:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

注意这里的RUST_BACKTRACE=1 环境变量,设置该变量后可以看到详细的报错信息

$ RUST_BACKTRACE=1 cargo run
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', src/main.rs:4:5
stack backtrace:
   0: rust_begin_unwind
             at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/panicking.rs:483
   1: core::panicking::panic_fmt
             at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/panicking.rs:85
   2: core::panicking::panic_bounds_check
             at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/panicking.rs:62
   3: >::index
             at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/slice/index.rs:255
   4: core::slice::index:: for [T]>::index
             at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/slice/index.rs:15
   5:  as core::ops::index::Index>::index
             at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/alloc/src/vec.rs:1982
   6: panic::main
             at ./src/main.rs:4
   7: core::ops::function::FnOnce::call_once
             at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/ops/function.rs:227
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

Result 来处理可恢复的异常

#![allow(unused)]
fn main() {
enum Result {
    Ok(T),
    Err(E),
}
}

举个栗子

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

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

    let f = match f {
        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)
            }
        },
    };
}

程序可以运行,但是太多的match了,换种写法(使用闭包closure)

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

fn main() {
   let f = 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);
       }
   });
}

更精简的写法

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

或者
let f = File::open("hello.txt").expect("Failed to open hello.txt");

异常的传播Propagating exception

fn read_username_from_file() -> Result {
    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),
    }
}

问号操作符?简化异常传播

#![allow(unused)]
fn main() {
use std::fs::File;
use std::io;
use std::io::Read;

fn read_username_from_file() -> Result {
    let mut f = File::open("hello.txt")?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}
}

可以简化上述代码

fn read_username_from_file() -> Result {
    let mut s = String::new();
    File::open("hello.txt")?.read_to_string(&mut s)?;
    Ok(s)
}

还可以进一步简化

use std::fs;
use std::io;

fn read_username_from_file() -> Result {
    fs::read_to_string("hello.txt")
}

在main() 函数中返回Result,使用了Box,可以支持多种异常

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

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

    Ok(())
}

如何决定是否panic!

如下struct Guess,如果初始化的值超出范围,给出panic!

#![allow(unused)]
fn main() {
pub struct Guess {
    value: i32,
}

impl Guess {
    pub fn new(value: i32) -> Guess {
        if value < 1 || value > 100 {
            panic!("Guess value must be between 1 and 100, got {}.", value);
        }

        Guess { value }
    }

    pub fn value(&self) -> i32 {
        self.value
    }
}
}

你可能感兴趣的:(Rust编程语言-9-异常处理)