Frage Sind verschachtelte Matches eine schlechte Übung im idiomatischen Rust?


Ich habe ein get_url_content Funktion und kümmern sich nicht um Fehler (es ist nur ein Test). Es gibt ein 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
        }
    }
}

Diese Funktion funktioniert gut, aber ich finde es nicht einfach zu lesen. Ich denke, es gibt einige Best Practices für diese Art von Fall, um es lesbarer zu machen. Sind verschachtelte Übereinstimmungen eine schlechte Übung (wie Rückruf-Hölle in JS) und wenn ja, wie kann man das vermeiden?


5
2017-07-22 09:26


Ursprung


Antworten:


Der einfachste Weg, die Dinge ein wenig sauberer zu machen, besteht darin, einige Klammern zu entfernen:

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

Das innere Spiel kann vielleicht etwas sauberer ausgedrückt werden

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

    Err(_) => None,
}

Dies legt nahe, a map auf dem äußeren Typ (um zu bekommen Result<Option<_>, _>) und dann das Ergebnis mit fallen lassen .unwrap_or(None)

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

6
2017-07-22 10:10



Result und Option habe einige großartige Methoden, um solchen Code einfacher zu machen.

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

Ich empfehle, die Dokumentation zu lesen Ergebnis und Möglichkeit; Es gibt Methoden für die meisten Kombinationen von Konvertierungen zwischen ihnen und entweder auf die Erfolgs- oder die Fehlerhälfte.

Wenn du dich ändern kannst get_url_content zurückgeben Result, Würde ich das empfehlen (siehe die Dokumentation zur Fehlerbehandlung. Mit Ihrem eigenen Fehlertyp und einigen Implementierungen von Fromwird die Funktion dann (

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

Und wahrscheinlich noch einfacher mit dem Neuen ? Operator.


4
2017-07-22 09:42