zoukankan      html  css  js  c++  java
  • Rust中的Result枚举

    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)
        });
    作者:菩提树下的杨过
    出处:http://yjmyzz.cnblogs.com
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    php中的高危函数
    PHP 站点相对包含,路径的问题解决方法(include,require)
    PHP中::、-&gt;、self、$this操作符的区别
    C#常用类库(100多个)
    Android滑动菜单特效实现,仿人人客户端侧滑效果,史上最简单的侧滑实现
    转载:Android调用相册、拍照实现缩放、切割图片
    在浏览器上直接输入url 时,中文传参乱码问题
    一个asp采集程序
    c#微信开发 转
    如何使用JS来检测游览器是什么类型,或android是什么版本号- 转载
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/15615227.html
Copyright © 2011-2022 走看看