Ich habe Rusts Dokumentation durchforstet und versucht, ein einfaches esoterisches Beispiel für meinen eigenen Bildungsnutzen auszuführen, mehr als nur praktisch. Während ich das tue, kann ich nicht den Kopf darüber verschließen, wie Rusts Fehlerbehandlung verwendet werden soll.
Das Programmierbeispiel, das ich verwende, ist eine Funktion zu schreiben, die einen Befehl in einer Shell ausführt. Aus dem Ergebnis des Befehls möchte ich stdout
(als String
oder &str
) abrufen und wissen, ob der Befehl fehlgeschlagen ist oder nicht.
Die std::process::Command
Struktur gibt mir die Methoden, die ich will, aber es scheint dass der einzige Weg sie zu kombinieren kludgy und peinlich ist:
Insbesondere scheinen die verschachtelten Match-Blöcke innerhalb von run_cmd
wirklich peinlich zu sein, und die verschachtelten Match-Blöcke in main
sind sogar noch schlimmer.
Was ich wirklich gerne machen würde, wäre eine allgemeinere Fehlerklasse als FromUtf8Error
oder io::Error
, die ich einfach in einen konkreten Typ umwandeln kann, aber es erscheint nicht der Typ System wurde auf diese Weise entworfen, also musste ich das rohe CmdError
eher als einen Unionstyp verwenden / p>
Ich bin mir sicher, dass es einen einfacheren Weg gibt, dies zu tun, der idiomatischer ist, aber ich habe es nicht aus der Dokumentation gefunden, die ich bisher gelesen habe.
Alle Zeiger werden geschätzt.
Dinge wie diese zu definieren, ist derzeit keine besonders nette Sache; Es gibt ein paar Dinge, die Sie mit Ihrem benutzerdefinierten Fehlertyp einrichten müssen, aber nachdem Sie das erledigt haben, sind die Dinge viel einfacher.
Zuerst möchten Sie std::error::Error
für CmdError
implementieren (was std::fmt::Display
und std::fmt::Debug
erfordert), und dann, damit try!
automatisch arbeiten kann, std::convert::From<std::string::FromUtf8Error>
und std::convert::From<std::io::Error>
. Hier sind die Implementierungen von denen:
(Die description
-Methode in der Error
-Implementierung könnte möglicherweise einen String zurückgeben, der nicht auf dem umgebrochenen Fehler basiert, zB "Befehl fehlgeschlagen". Wenn man die Details möchte, sind sie immer noch in Error.cause()
.)
Nach der Implementierung dieses Loses sind die Dinge viel einfacher, weil wir try!
. run_cmd
kann so geschrieben werden:
Da try!
die From
-Infrastruktur verwendet, ist dies alles viel einfacher; Die erste Zeile gibt möglicherweise Err(CmdError::IoError(_))
zurück (für Command.output()
gibt Result<_, io::Error>
zurück) und die zweite Zeile gibt möglicherweise Err(CmdError::UtfError(_))
zurück (für String::from_utf8(…)
gibt Result<_, FromUtf8Error>
zurück).
Ihr main
kann auch etwas einfacher sein, wenn der Zweig err
keinen weiteren Abgleich benötigt, wenn Sie sich nicht für den speziellen Fehler interessieren; Da es jetzt fmt::Display
implementiert, können Sie es einfach direkt verwenden.
Übrigens sollte {:}
in einer Formatzeichenfolge als {}
geschrieben werden; Das :
ist überflüssig, wenn nichts folgt. ( {:?}
würde funktionieren, wenn Debug
output angezeigt wird. Sie sollten jedoch Display
verwenden, wenn es auf den Benutzer ausgerichtet ist.)
Tags und Links rust