Ich schreibe eine Funktion, die über einen Vektor von Result
iteriert und Erfolg zurückgibt, wenn alle erfolgreich waren, oder einen Fehler, wenn einer fehlgeschlagen ist. Einschränkungen in error::Error
frustrieren mich und ich bin mir nicht sicher, wie ich sie umgehen soll. Derzeit habe ich so etwas wie:
let mut errors = Vec::new();
for result in results {
match result {
Err(err) => errors.push(err),
Ok(success) => { ... }
}
}
if errors.is_empty() {
return Ok(())
else {
return Err(MyErrorType(errors))
}
Das Problem bei meinem aktuellen Ansatz ist, dass ich nur einen Fehler als cause
von MyErrorType
festlegen kann und der description
meines Fehlers ein statischer String
sein muss, damit ich dies kann Enthält nicht die Beschreibungen der einzelnen Auslösefehler. Alle Fehler sind möglicherweise für den Anrufer relevant.
2 Antworten
Es gibt keine Konvention, die ich kenne, und tatsächlich hatte ich nie das Problem, mehrere Fehler gleichzeitig zu melden ...
... Davon abgesehen gibt es zwei Punkte, die Ihnen helfen können:
Es gibt keine Einschränkung, dass die Beschreibung
'static
String
ist. Sie verwechseln wahrscheinlich&'static str
und&str
. Infn description(&self) -> &str
ist die Lebensdauer vonstr
mit der Lebensdauer vonself
(Lebensdauerelision) verknüpft, und daher erfüllt ein eingebettetesString
die EinschränkungenError
ist eine Schnittstelle, um Fehler einheitlich zu behandeln. In diesem Fall war zwar nur ein einzigescause
vorgesehen, dies schließt jedoch einen spezifischeren Typ nicht aus, um mehrere Ursachen zu aggregieren, und daError
Downcasting zulässt (Error::is
, {{X4}) }, ...) Der spezifischere Typ kann vom Handler abgerufen und vollständig abgefragt werden
Daher würde ich vorschlagen, dass Sie einen neuen konkreten Typ erstellen, der ausschließlich dazu dient, mehrere Fehler (in einem Vec<Box<Error>>
) zu speichern und die Error
-Schnittstelle zu implementieren. Es liegt an Ihnen, über die Beschreibung zu entscheiden und sie freizulegen.
Mit einem einzigen Typ können Ihre Kunden leichter auf Downcasting testen als mit einer unbekannten (und möglicherweise mit der Zeit wachsenden) Anzahl potenzieller Downcasting-Ziele.
Erweitern Sie Punkt 1 von Matthieus guter Antwort ein wenig. Der Punkt, an dem Sie wahrscheinlich auf Probleme stoßen (ich weiß, dass ich es getan habe, als ich versucht habe, Error
zu implementieren), ist, dass Sie ein dynamisches description()
haben möchten.
// my own error type
#[derive(Debug)] struct MyError { value: u8 }
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "bummer! Got a {}", self.value)
}
}
// I am now tempted to add the problematic value dynamically
// into the description, but I run into trouble with lifetimes
// this DOES NOT COMPILE because the String I'm building
// goes out of scope and I can't return a reference to it
impl error::Error for MyError {
fn description(&self) -> &str {
&format!("can't put a {} here!", self.value)
}
}
Lösung 1
Erstellen Sie nicht dynamisch description()
. Verwenden Sie einfach eine statische str. Dies ist die die meisten Implementierungen von Error on github scheinen zu tun. Wenn Sie den Wert abrufen und anzeigen (oder protokollieren) müssen, können Sie jederzeit von Ihrem Typ MyError
darauf zugreifen. Mit Display
(das Sie für alle Fehlerimplikationen implementieren müssen) können Sie dynamische Zeichenfolgen erstellen.
Ich habe ein erfundenes Beispiel auf dem Spielplatz erstellt, das zeigt, wie mehrere verfolgt werden Fehler.
Lösung 2
(was Matthieu vorschlägt) Sie können die Fehlermeldung im Fehler selbst speichern.
#[derive(Debug)] struct MyError { value: u8, msg: String }
impl MyError {
fn new(value: u8) -> MyError {
MyError { value: value, msg: format!("I don't like value {}", value) }
}
}
// now this works because the returned &str has the same lifetime
// as self
impl error::Error for MyError {
fn description(&self) -> &str {
&self.msg
}
}
Neue Fragen
error-handling
Programmiersprachenkonstrukte zur Behandlung von Fehlern, die durch Fehlercodes, Ausnahmen oder andere sprachspezifische Mittel angezeigt werden.