Rust的错误处理

Rust中的错误处理:
ps:笔者是个刚接触Rust的菜鸟,本文也只是自己的一点粗浅的看法,如果有什么不对的地方欢迎指出,也希望能给大家一点小小的帮助
这下面两篇文章都是关于Rust的错误处理的文章:
https://lotabout.me/2017/rust-error-handling/
https://zhuanlan.zhihu.com/p/25506762
错误处理,目前接触最多的是Option<>,与Result<>,概念就不多说了,具体的可以查一下,也可以查看第一条链接的文章。
先说Option<>这个错误处理机制,一版用于为空的情况,在Rust中称之为None。
举个例子:

let vec = vec![1,2,3];
let a = vec.get(0);

根据动态数组的定义,变量a得到的值其实是个Option<&i32>。因为a有可能为None。
从代码可以看出,a明显为不为None,此时,Rust提供了一个方法,unwrap()。这个方法相当于:你程序员说部位None,那我就相信你,如果为None,那我就panic!,锅全部甩给你,和我没关系。于是就有这样的写法:

let vec1 = vec![1,2,3];
let a: &i32 = vec.get(0).unwrap();

这里明显看出,a的值为1,没什么问题,可以试着将get(0)改为get(4),运行程序会得到报错的结果。如果我们不能保证,得到的这个值是不是为空,我们可以这样写:

let vec1 = vec![1,2,3];
let a = vec.get(0);
if a == None {
    println!("a is None");
} else {
    println!("a")
}

当然这种写法很低级,当然有更高级的:unwrap_or()。该方法的意思为,如果a为空,则返回一个自定义的值,例如:

let vec = vec![1,2,3];
let a = vec.get(4).unwrap_or(&123)

其中123就是你自定义的值,如果a为空,则a的值就为123。还有跟高级的用法:unwrap_or_else()。该方法可以定义函数:

let vec = vec![1,2,3];
let a: &i32 = vec.get(0).unwrap_or_else(||{
    &123
});

当然,可以使用最原始的方法:match,但是个人觉得这种方法太麻烦了。下一个成语就是
Result
Result是个枚举,enum Result {Ok(T),Err(E)}(option也是个枚举)。这
包含两个参数,T和E都是泛型类型参数。Result也可以利用unwrap()获取值,但是如果出错则panic。一般的用传统的写法为:
let f = File::open(“hello.txt”);

let f = match f {
    Ok(file) => file,
    Error(error) => {
        println!("Error!");
    }
};

这里用match写法,如果当结果为Ok时,返回file。当然也可以用unwrap():

let f = File::open("hello.txt").unwrap();

这里,如果出错,则会panic,和上面说的用法差不多。这里还引入了一个方法:expect:

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

expect与unwrap()的使用方式一致,返回文件,或者panic。但是expect用来调用panic!的错误信息将会作为参数传递给expect,而unwrap,使用的是默认的panic信息。我们知道,有时候panic信息很难看,一大堆错误信息,不能马上就定位错误,用expect,就可以根据上下文,写出错误所在。比如上面的代码,我们明显知道是打不开导致的错,这里就可以用expect来表示。这样还有个好处:我们自定义的错误信息将会更容易找到代码中的错误信息来自何处。如果在多处使用unwrap,则需要花更多的时间来分析到底是哪一个unwrap造成看panic,因为所有的unwrap调用都打印相同的信息。
当然,io这个库里有定义错误类型ErrorKind,也可以用这个判断错误类型,举个例子:

let path = Path::new("hello.txt");
let mut file = File::open(&path).map_err(|error| {
    if error.kind() ==  io::ErrorKind::NotFound {
        File::create(&path).unwrap()
    }else {
        println!("{}","some error happened!can not open the target file");
    }
});

不仅仅io提供ErrorKind,还有很多三方库提供的,可根据实际情况进行使用。传播错误:使用?进行传播。什么意思呢?就是错误我不处理,将错误传给调用我的人,有点类似于java中的throw。所以,?只能用在返回值是Result的函数中。?号作用是:传播错误,返回的是一个Result,要求这个函数必须有返回,且是Result类型,或者是option类型,或者其他实现了std::ops::Try的类型。一般地,在Rust中,如果确定不了其值(有可能为空),则用Option作为返回值。如果执行什么操作的时候会出现异常,则返回Result。Ok(())返回的就是Result。
我们在写函数的时候,可以将Result作为返回值传递,那问题来了,调用函数的怎么获取值啊?用unwrap啊,笨。

fn read(size: usize) -> Result {
    if size >= 2 {
        return Ok(size);
    } else {
        return Err(12);
    }
}

我们可以将需要返回的值这样封装,这样也可以自定义错误,非常好用。当然,Result和Option都有些高级用法,比如说,and_then,map_err等。但是目前还没研究到那么深刻。现在这些知识在写代码是够用的,但是补好看,用了那些高级用法,你的代码看起来会更高大上,更整洁啊,有木有。这个后面再抽时间慢慢研究吧。

你可能感兴趣的:(知识总结,知识笔记)