Ein häufig verwendeter Vertrag für Funktionen, die einen Fehlerwert eines Schnittstellentyps zurückgeben, besteht darin, dass der Aufrufer im Voraus nichts über den Status anderer von diesem Aufruf zurückgegebener Werte wissen muss, ohne zuvor den Fehler zu überprüfen.
In den meisten Fällen sollten von Funktionen zurückgegebene Fehlerwerte für den Aufrufer undurchsichtig sein. Das heißt, ein Test, bei dem der Fehler Null ist, zeigt, ob der Anruf erfolgreich war oder fehlgeschlagen ist, und das ist alles, was Sie tun müssen.

Bild von hier
Bei einer kleinen Anzahl von Fällen, die normalerweise mit Interaktionen mit der Außenwelt verbunden sind, wie z. B. Netzwerkaktivitäten, muss der Anrufer die Art des Fehlers untersuchen, um zu entscheiden, ob der Vorgang wiederholt werden soll.
Eine häufige Anforderung für Paketautoren besteht darin, bekannte Fehler vom öffentlichen Typ zurückzugeben, damit der Aufrufer den Typ assert verwenden und diese detailliert untersuchen kann. Ich glaube, dass diese Praxis zu einer Reihe unerwünschter Ergebnisse führt:
- Offene Fehlertypen vergrößern den "Kontaktbereich" mit der Paket-API.
- Neue Implementierungen sollten nur die in der Schnittstellendeklaration angegebenen Typen zurückgeben, auch wenn sie nicht gut passen.
- Die Art des Fehlers kann nach dem Hinzufügen zum Code nicht ohne Unterbrechung der Kompatibilität geändert oder veraltet werden, wodurch die API anfällig wird.
Bestätigen Sie das erwartete Verhalten, nicht den Fehlertyp
Behaupten Sie nicht, dass der Fehlerwert ein bestimmter Typ ist, sondern behaupten Sie, dass der Wert ein bestimmtes Verhalten implementiert.
Dieser Satz stimmt mit der Natur der impliziten Go-Schnittstellen überein und ist kein [Subtyp] der Natur von vererbungsbasierten Sprachen. Betrachten Sie dieses Beispiel:
func isTimeout(err error) bool { type timeout interface { Timeout() bool } te, ok := err.(timeout) return ok && te.Timeout() }
Der Aufrufer kann mithilfe von isTimeout () ermitteln, ob das Zeitlimit für den Fehler abgelaufen ist, indem er die Zeitüberschreitungsschnittstelle implementiert, und dann bestätigen, ob das Zeitlimit für den Fehler abgelaufen ist - alles ohne Kenntnis des Typs oder der Quelle Fehlerwerte.
Diese Methode ermöglicht es, Fehler in der Regel mit Bibliotheken zu versehen, die dem Fehlerpfad Erklärungen hinzufügen. vorausgesetzt, die umschlossenen Fehlertypen implementieren auch die Fehlerschnittstellen, die sie umschließen.
Dies mag als unlösbares Problem erscheinen, aber in der Praxis gibt es einige allgemein akzeptierte Schnittstellenmethoden, sodass Timeout () bool und Temporary () bool eine breite Palette von Anwendungsfällen abdecken.
Abschließend
Bestätigen Sie das erwartete Verhalten, nicht den Fehlertyp
Für Paketautoren
Wenn Ihr Paket temporäre Fehler generiert, stellen Sie sicher, dass Sie Fehlertypen zurückgeben, die die entsprechenden Schnittstellenmethoden implementieren. Wenn Sie Ausgabefehlerwerte umbrechen, stellen Sie sicher, dass Ihre Wrapper die Schnittstelle (n) unterstützen, mit denen der ursprüngliche Fehlerwert implementiert wird.
Für Paketbenutzer
Wenn Sie nach einem Fehler suchen müssen, verwenden Sie die Schnittstellen, um das erwartete Verhalten und nicht die Art des Fehlers zu bestätigen. Fragen Sie die Paketautoren nicht nach offenen Fehlertypen. Bitten Sie sie, ihre Typen an allgemeinen Schnittstellen auszurichten, indem Sie die Methoden Timeout () oder Temporary () angeben.
Über den Autor
Der Autor dieses Artikels, Dave Cheney , ist Autor vieler beliebter Pakete für Go, z. B. https://github.com/pkg/errors und https://github.com/davecheney/httpstat .
Vom Übersetzer
Obwohl der ursprüngliche Artikel auf Ende 2014 datiert ist, scheint es mir, dass er seine Relevanz nicht verloren hat. Der beschriebene Ansatz ist in wenigen Paketen enthalten, während der Rest den üblichen Ansatz für Fehler verwendet.
Änderungen am Text zur Erhöhung der Klarheit des Materials sind willkommen!