嵌套匹配在惯用Rust中是不好的做法吗?

时间:2016-07-22 09:26:01

标签: rust

我有一个get_url_content函数而不关心错误(这只是一个测试)。它返回Option<String>

extern crate hyper;

use std::io::Read;
use hyper::client::Client;

fn get_url_content(url: &str) -> Option<String> {
    let client = Client::new();
    let mut s = String::new();

    match client.get(url).send() {
        Ok(mut res) => {
            match res.read_to_string(&mut s) {
                Ok(_) => {
                    Some(s)
                },
                Err(_) => {
                    None
                }
            }
        },
        Err(_) => {
            None
        }
    }
}

此功能正常但我发现它不容易阅读。我认为有一些关于此类案例的最佳实践,以使其更具可读性。嵌套匹配是不好的做法(如JS中的回调地狱),如果是,如何避免它?

2 个答案:

答案 0 :(得分:9)

让事情变得更清洁的最简单方法是放下一些括号:

match client.get(url).send() {
    Ok(mut res) =>
        match res.read_to_string(&mut s) {
            Ok(_) => Some(s),
            Err(_) => None,
        },
    Err(_) => None,
}

内部匹配可以表达得更清晰一点

match client.get(url).send() {
    Ok(mut res) =>
        res.read_to_string(&mut s).ok().map(|_| s),

    Err(_) => None,
}

这表示在外部类型上使用map(获取Result<Option<_>, _>),然后使用.unwrap_or(None).unwrap_or_default()

删除结果
client.get(url).send()
      .map(|mut res| res.read_to_string(&mut s).ok().map(|_| s))
      .unwrap_or(None)

答案 1 :(得分:4)

ResultOption有一些很好的方法可以让代码变得更简单。

fn get_url_content(url: &str) -> Option<String> {
    let client = Client::new();

    let res = client.get(url)
                    .send()
                    .ok()  // Convert to Option, discarding error
                    .and_then(|mut res| {
                        let mut s = String::new();
                        let result = res.read_to_string(&mut s);
                        result.ok().map(|_| s)
                     }
           })
}

我建议查看ResultOption的文档;它们之间存在大多数转换组合的方法,并且对成功或错误的一半采取行动。

如果您可以更改get_url_content以返回Result,我建议您(请参阅the error handling documentation。使用您自己的错误类型和From的某些实现,该功能然后变成(

fn get_url_content(url: &str) -> Result<String, MyError> {
    let client = Client::new();
    let mut s = String::new();

    let got = try!(client.get(url));
    let sent = try!(got.send());
    try!(sent.read_to_string(s));
    Ok(s)
}

使用新的?运算符可能更简单。