Rust中的Result枚举
2023-03-20 14:56:04 时间
Result枚举在Rust中是使用频率极高的一个类型,常用于函数的返回值定义,其源码如下:
#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
#[must_use = "this `Result` may be an `Err` variant, which should be handled"]
#[rustc_diagnostic_item = "result_type"]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Result<T, E> {
/// Contains the success value
#[lang = "Ok"]
#[stable(feature = "rust1", since = "1.0.0")]
Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
/// Contains the error value
#[lang = "Err"]
#[stable(feature = "rust1", since = "1.0.0")]
Err(#[stable(feature = "rust1", since = "1.0.0")] E),
}
抛开一堆#开头的trait不看,核心就是Ok及Err这2个泛型成员。
先来看一个基本示例:
let result_ok: Result<String, String> = Result::Ok(String::from("success"));
let result = match result_ok {
Result::Ok(o) => o,
Result::Err(e) => e,
};
println!("{}", result);
这里定义了一个"成功"的Result,然后使用模式匹配对其进行处理,如果是Ok的,取出Ok的值,否则取出Err的值。这类简单重复的判断,经常会用到,rust封装了1个等效的方法:unwrap,其内部实现如下:
pub fn unwrap(self) -> T {
match self {
Ok(t) => t,
Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e),
}
}
其实就是模式匹配,取出Ok或Err的值。所以前面这个示例,可以改写成:
let result_ok: Result<String, String> = Result::Ok(String::from("success"));
// let result = match result_ok {
// Result::Ok(o) => o,
// Result::Err(e) => e,
// };
let result = result_ok.unwrap();
println!("{}", result);
unwrap源码中的unwrap_failed继续追下去的话,可以看到:
fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! {
panic!("{}: {:?}", msg, error)
}
调用了panic方法,这意味着如果Result返回的是Err,则程序会崩溃,可以试一把:
如果Err发生时不希望程序崩溃,可以使用unwrap_or()
let result_fail: Result<String, String> = Result::Err(String::from("failure"));
let result = result_fail.unwrap_or(String::from("err occur"));
println!("{}", result);
unwrap_or可以传入一个default缺省的错误值,上面这段将输出“err occur”。但这样一来,就把原始的错误信息failure给丢失了! 不用担心,rust早考虑到了:
let result_fail: Result<String, String> = Result::Err(String::from("failure"));
let result = result_fail.unwrap_or_else(|e|e);
println!("{}", result);
使用unwrap_or_else传入1个闭包匿名函数,可以随心所欲的对原始错误进行处理,这里我们啥也没干,|e|e,表示原样返回。
Result枚举还提供了其它一些常用方法,参见上图,有兴趣的同学,可以研究下源码。
最后来看一个稍微复杂点的示例:在当前目录下,打开hello.txt文件,如果该文件不存在,则自动创建一个空的hello.txt。
use core::panic;
use std::fs::File;
use std::io::{ErrorKind};
fn main() {
let file_name = String::from("hello.txt");
//第1层match
match File::open(&file_name) {
Ok(file) => file,
//第2层match
Err(error) => match error.kind() {
//第3层match
ErrorKind::NotFound => match File::create(&file_name) {
Ok(fc) => fc,
Err(e) => panic!("Error creating file:{:?}", e),
},
oe => panic!("Error opening the file:{:?}", oe),
},
};
}
用了3层模式匹配(match套娃),看上去比较原始,如果不喜欢这种match写法,可以用今天学到的知识,换成相对“正常点”的写法:
File::open(&file_name).unwrap_or_else(|e| {
if e.kind() == ErrorKind::NotFound {
File::create(&file_name).unwrap_or_else(|e| {
panic!("Error creating file:{:?}", e);
})
} else {
panic!("Error opening file:{:?}", e)
}
});
Rust程序员可能会写得更简短:
File::open(&file_name).unwrap_or_else(|e| match e.kind() {
ErrorKind::NotFound => {
File::create(&file_name).unwrap_or_else(|e| panic!("Error creating file:{:?}", e))
}
_ => panic!("Error opening file:{:?}", e)
});
相关文章
- 金融服务领域的大数据:即时分析
- 影响大数据、机器学习和人工智能未来发展的8个因素
- 从0开始构建一个属于你自己的PHP框架
- 如何将Hadoop集成到工作流程中?这6个优秀实践必看
- SEO公司使用大数据优化其模型的5种方法
- 关于Web Workers你需要了解的七件事
- 深入理解HTTPS原理、过程与实践
- 增强分析:数据和分析的未来
- PHP协程实现过程详解
- AI专家:大数据知识图谱——实战经验总结
- 关于PHP的错误机制总结
- 利用数据分析量化协同过滤算法的两大常见难题
- 怎么做大数据工作流调度系统?大厂架构师一语点破!
- 2019大数据处理必备的十大工具,从Linux到架构师必修
- OpenCV中的KMeans算法介绍与应用
- 教大家如果搭建一套phpstorm+wamp+xdebug调试PHP的环境
- CentOS下三种PHP拓展安装方法
- Go语言HTTP Server源码分析
- Go语言HTTP Server源码分析
- 2017年4月编程语言排行榜:Hack首次进入前五十