rust一些习惯表达方法

学习rust的朋友可能经常看到Result和Option,虽然不一定直接看到他们本身,但是他们的方法还是常见的,比如:xxx.ok().expect(“…”);
这个xxx一般就是某个函数返回的Result类型了,下面就详细的讲解下他们的来源

现在看看rust book里的那个guess game,有这么一段:
http://doc.rust-lang.org/book/guessing-game.html

use std::io;

fn main() {
    println!("Guess the number!");

    println!("Please input your guess.");

    let mut guess = String::new();

    io::stdin().read_line(&mut guess)
        .ok()
        .expect("Failed to read line");

    println!("You guessed: {}", guess);
}

前面几行都好理解,我们看看10~12行的几个ok,expect到底是什么

理解这些内容最好的方法就是看源代码,不过大家别慌,不是要你从头开始啃rust所有源码,只需要有针对性的看就可以了
大家记住下面这个常用的链接,这儿可以查到rust的所有源代码,可以搜索,反应速度非常快:
https://doc.rust-lang.org/std/

1、io::stdin()

现在从头开始,先看io::stdin()这个是什么

这个网页的最上方就是输入框了,我们一步步来,先输入 io::stdin
注意:不要加后面括号
下面就是搜索的结果,可以看到第二行就是我们要找的函数(第一行是结构体,我们要找的是函数)
这里写图片描述

点击进去就可以查看源代码了,这个函数声明很简单,只是返回了一个Stdin的结构体
这里写图片描述

如果想看源代码就点右上角的那个src,见上图右上角红色框

我们现在不需要去看源代码了,现在看看Stdin的介绍就可以了,看图上左边的红色框里的Stdin是可以点击的,点进去然后找到read_line方法:

fn read_line(&mut self, buf: &mut String) -> Result<usize>[−]

Locks this handle and reads a line of input into the specified buffer.

For detailed semantics of this method, see the documentation on BufRead::read_line.

上面是read_line的介绍,我们不去关心他的实现过程了,先看看他返回的类型是:

Result<usize>

2、Result

点进去看看Result的页面,这个就是这篇blog的重点了

type Result<T> = Result<T, Error>;

A type for results generated by I/O related functions where the Err type is hard-wired to io::Error.

This typedef is generally used to avoid writing out io::Error directly and is otherwise a direct mapping to std::result::Result.

上面的介绍部分说的是io::Result其实是为了书写方便定义的,他用io::Error类型替代了std::result::Result<T,Error>里的Error类型

这样io::Result比std::result::Result更加具体化了,那么写起来也相对简单了,他只可能返回io::Error类型的错误

因为这儿io::Result只是个类型定义,所以我们要去看std::result::Result的源代码,搜索过程就不详述了,具体看源码:

pub enum Result<T, E> {
    /// Contains the success value
    #[stable(feature = "rust1", since = "1.0.0")]
    Ok(T),

    /// Contains the error value
    #[stable(feature = "rust1", since = "1.0.0")]
    Err(E)
}

上面就是定义了,可以看到他是个enum,有OK和Err类型,分别对应了Result泛型里的类型T和E,std::result::Result里并没有限制E和T的类型,但是io::Result就把E的类型限制成了io::Error,这个大家注意下就好

说了这么多我们再看看问题

io::stdin().read_line(&mut guess)
        .ok()
        .expect("Failed to read line");

刚才我们确认了read_line返回的是io::Result<T>类型,那么ok()函数肯定就是Result的一个方法了,继续看std::result::Result的方法实现的源代码:

    pub fn ok(self) -> Option<T> {
        match self {
            Ok(x)  => Some(x),
            Err(_) => None,
        }
    }

3、Option

可以看到ok函数返回的是Option<T>,还是没有返回我们最终想要的类型T,我们还是先看看ok的代码吧。

其实这个函数非常简单,就是一个match,如果没有出错用Option::Some把我们要的数据用包装下返回;如果出错了就返回Option::None

这样皮球又提到了Option去了…我们再继续查Option:

pub enum Option<T> {
    None,
    Some(T),
}

上面就是Option的定义,也是个enum。其中None顾名思义就是“没有”,他没有包装类型T,所以他真的什么都没。Some带来我们的类型T,所以现在目标已经很静了,只要把T对应的数据弄出来就最终得到了我们要的数据了

继续看这个代码,ok()返回的是Option,那么expect肯定就是Option的方法了

io::stdin().read_line(&mut guess)
        .ok()
        .expect("Failed to read line");

继续看Option源代码,看他方法的实现:

    pub fn expect(self, msg: &str) -> T {
        match self {
            Some(val) => val,
            None => panic!("{}", msg),
        }
    }

终于看到想要的返回类型了:T,这个就是我们最终要的数据了,看read_line返回的是io::Result<usize>,所以这儿返回的是一个uszie类型的长度,不过guess game里并没有使用他

可以看到这个函数也是个match,如果是Some能匹配了就把他携带的数据返回;如果是None类型说明这个Option根本就没携带数据,也就是前面的Result出错了,所以会调用panic!宏把你传递进去的字符串打印出来并且退出程序。

4、其他写法

现在绕了一大圈终于找到T了,其实ok().expect(…);这种只是偷懒的写法,出错了直接打印你的字符串就退出程序了。当然有更偷懒的,看std::result::Result的代码:

pub fn unwrap(self) -> T {
        match self {
            Ok(t) => t,
            Err(e) =>
                panic!("called `Result::unwrap()` on an `Err` value: {:?}", e)
        }
    }

那么代码就可以写成下面这样就可以了:

io::stdin().read_line(&mut guess).unwrap();

这个是非常不建议的用法,除非你非常肯定read_line不可能出错

虽然这个read_line结果我们并没有使用,但是还是需要处理一下,不然Result没有处理编译器会给警告的

处理result最直接和直观的方法就是直接match,不需要通过Option中转了:

match io::stdin().read_line(&mut guess) {
    Ok(size)=>xxxx,
    Err(e)=>xxx,
}

xxx处换成你自己的代码就可以了

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值