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

rap*_*2-h 11 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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Vee*_*rac 10

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

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

内心的比赛可以表达得更清洁一些

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

    Err(_) => None,
}
Run Code Online (Sandbox Code Playgroud)

这建议map在外部类型上使用a (获取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)
Run Code Online (Sandbox Code Playgroud)


Chr*_*son 7

Result并且Option有一些很棒的方法可以让这样的代码更简单。

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)
                     }
           })
}
Run Code Online (Sandbox Code Playgroud)

我建议查看ResultOption的文档;它们之间的大多数转换组合都有方法,并根据成功或错误的一半进行操作。

如果您可以更改get_url_content为返回 a Result,我建议您这样做(请参阅错误处理文档。使用您自己的错误类型和 的某些实现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)
}
Run Code Online (Sandbox Code Playgroud)

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