9.Rust错误处理

错误处理是程序开发中必不可少的一个环节,在Rust中,错误分成两个类别:可恢复错误和不可恢复错误。
可恢复错误:比如说未找到文件,Rust中用Result来实现
不可恢复错误:比如数组访问越界,Rust中用panic!实现

1.panic!

这个有感叹号,很显然是一个宏,我们来使用一下子。

fn main() {
    panic!("panic here!");
}

报错信息:

thread 'main' panicked at 'panic here!', src\main.rs:2:5
stack backtrace:
   0: backtrace::backtrace::trace_unsynchronized
...
这底下还有很多调用堆栈的信息哈,我们现在不去关心它

使用RUST_BACKTRACE=1命令来运行程序也可以调出调用堆栈信息。

2.Result

Result其实是一个枚举类型,它的原型如下:

enum Result {
	Ok(T),
	Err(E),
}

我们通过打开文件来举例说明:

use std::fs::File;

fn main() {
    let f = File::open("Rust.txt");
    //枚举当然需要来match一下
    let f = match f {
        Ok(file) => file,
        Err(error) => panic!("error: {}", error),
    };
}

我们的当前目录里并没有这个文件,预期是会出错的。

报错信息:

thread 'main' panicked at 'error: 系统找不到指定的文件。 (os error 2)', src\main.rs:8:23
stack backtrace:
   0: backtrace::backtrace::trace_unsynchronized

emmm,我这里居然还是中文!。。。我以为是No such a file or directory.

3.简写形式

我们可以通过unwrap或者expect函数来简写程序。

use std::fs::File;

fn main() {
//    let f = File::open("Rust.txt");
//    //枚举当然需要来match一下
//    let f = match f {
//        Ok(file) => file,
//        Err(error) => panic!("error: {}", error),
//    };
    let f = File::open("Rust.txt").unwrap();
}

报错信息:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "系统找不到指定的文件。" }', src\libcore\result.rs:1165:5
stack backtrace:
   0: backtrace::backtrace::trace_unsynchronized
use std::fs::File;

fn main() {
    let f = File::open("Rust.txt").expect("failed to open Rust.txt");
}

报错信息:

thread 'main' panicked at 'failed to open Rust.txt: Os { code: 2, kind: NotFound, message: "系统找不到指定的文件。" }', src\libcore\result.rs:1165:5
stack backtrace:
   0: backtrace::backtrace::trace_unsynchronized
4.传播错误

当我们调用一个函数的时候,函数内部可能出错,而调用方需要捕捉错误信息,因此可以将错误传出来,这个过程就是传播错误。

还是以读取文件内容来举例:

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

fn main() {
    let res = read_file();
    match res {
        Ok(str) => println!("str: {}", str),
        Err(error) => println!("error: {}", error)
    };
}

fn read_file() -> Result {
    let f = File::open("Rust.txt");
    let mut f = match f {
        Ok(file) => file,
        Err(error) => return Err(error)
    };

    let mut str = String::new();
    match f.read_to_string(&mut str) {
        Ok(_) => Ok(str),
        Err(error) => Err(error)
    }
}

我们创建了一个Rust.txt文件,运行结果如下:

str: Rust编程之路

我们把文件删除:

运行结果:

error: 系统找不到指定的文件。 (os error 2)

也是把错误信息打印出来了。

5.小问号,你是否有很多朋友?

我们可以通过“?”,来做到传播错误的简写:

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

fn main() {
    let res = read_file();
    match res {
        Ok(str) => println!("str: {}", str),
        Err(error) => println!("error: {}", error)
    };
}

fn read_file() -> Result {
    let mut f = File::open("Rust.txt")?;

    let mut str = String::new();
    f.read_to_string(&mut str)?;
    Ok(str)
}

还可以再简单一点:

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

就很棒!

6.panic!和Result如何选择?

在测试过程中,我们可以使用panic!,这样调试起来比较方便。

但是在正式发布的代码中,为了程序的健壮性和容错率,最好不要使用panic!

个人观点哈~

7.panic的实现机制

在Rust中,panic的实现方式有两种:unwind和abort

unwind 方式在发生panic 的时候,会一层一层地退出函数调用枝,在此过程中,当前栈内的局部变量还可以正常析构。
abort 方式在发生panic 的时候,会直接退出整个程序。

一般来说,默认情况下,编译器都是使用的unwind模式。

如何用户自己制定:

rustc -C panic=unwind test.rs
rustc -C panic=abort test.rs

你可能感兴趣的:(Rust编程入门系列)