问题
I have a get_url_content
function and don't care about errors (it's just a test). It returns an 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
}
}
}
This function works fine but I find it's not easy to read. I think there are some best practices about this kind of case to make it more readable. Are nested matches a bad practice (like callback hell in JS) and if so, how to avoid it?
回答1:
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)
回答2:
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.
来源:https://stackoverflow.com/questions/38522870/are-nested-matches-a-bad-practice-in-idiomatic-rust