Are nested matches a bad practice in idiomatic Rust?

Result and Option have some great methods for making code like that simpler.

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)
                     }
           })
}

I recommend looking through the documentation for Result and Option; there are methods for most combinations of conversions between them, and acting on either the success or error half.

If you can change get_url_content to return a Result, I would recommend that (see the error handling documentation. With your own error type and some implementations of From, the function then becomes (

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)
}

And probably even simpler with the new ? operator.


The easiest way to make things a bit cleaner is to drop some braces:

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

The inner match can be expressed a little cleaner perhaps as

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

    Err(_) => None,
}

This suggests using a map on the outer type (to get Result<Option<_>, _>) and then dropping the result with .unwrap_or(None) or .unwrap_or_default()

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

Tags:

Rust