[Golang-Fehlerbehandlung] Der beste Weg, die Verarbeitung nach der Art des Fehlers aufzuteilen

Einführung

Ich habe versucht herauszufinden, welche Methode es gibt, wenn Sie die Verarbeitung abhängig von der Art des Fehlers in Golang ändern möchten.

Das liegt daran, dass ** Golang Try-Catch nicht unterstützt. ** **. Also fing ich an, diesen Artikel zu schreiben, als ich herausfinden wollte, wie Golang Java-Try-Catch-ähnliche Funktionen implementieren kann.

Über den Gesamtüberblick des Artikels. Zunächst werde ich vier häufig verwendete Funktionen des Fehlerpakets erläutern. -Nächste werden wir drei mögliche Methoden versuchen, um die Verarbeitung abhängig von der Art des Fehlers zu ändern. -Und die Schlussfolgerung, wie die Verarbeitung am besten nach der Art des Fehlers aufgeteilt werden kann. Wir werden in dieser Reihenfolge fortfahren.

4 häufig verwendete Funktionen des Fehlerpakets

Das Standardfehlerpaket verfügt nicht über die folgenden Funktionen.

--Bestimmen der Art des Fehlers, der zuerst aufgetreten ist

Grundsätzlich verwenden wir das Paket Fehler. Werfen wir einen Blick auf die Funktion von Fehlern.

Funktion 1 func Neuer Fehler (Nachrichtenzeichenfolge)

Es wird verwendet, wenn ** einfach ein Fehler generiert ** wird, indem es wie unten gezeigt in der Zeichenfolge der Fehlermeldung angegeben wird.

err := errors.New("Ella~Korrekt~Hmm")
fmt.Println("output: ",err)
// output:Ella~Korrekt~Hmm

Funktion 2 func Fehler (Formatzeichenfolge, Argumente ... Schnittstelle {}) Fehler

Es wird verwendet, um einen Fehler zu generieren, indem das ** Format und die Fehlerzeichenfolge wie unten gezeigt angegeben werden.

err := errors.Errorf("output: %s", "Ella~Korrekt~Hmm")
fmt.Printf("%+v", err)
// output:Ella~Korrekt~Hmm

Funktion 3 func Wrap-Fehler (Fehlerfehler, Nachrichtenzeichenfolge)

Es wird verwendet, wenn der ursprüngliche Fehler wie unten gezeigt verpackt wird.

err := errors.New("repository err")
err = errors.Wrap(err, "service err")
err = errors.Wrap(err, "usecase err")
fmt.Println(err)
// usecase err: service err: repository err

** Wichtiges Feature **, daher werde ich es etwas genauer erklären. Zum Beispiel, selbst wenn die Hierarchie tief ist, wie z. B. Usecase-Schicht → Service-Schicht → Repository-Schicht Durch Umschließen des ersten Fehlers können Sie die unteren Fehlerinformationen auf die obere Ebene bringen. Dadurch ist es einfacher, die Ursache des ** Fehlers zu identifizieren. ** ** **

Diesmal ist es mir auch egal, aber es scheint üblich zu sein, den Funktionsnamen in die Fehlermeldung aufzunehmen, um die Ursache schnell zu identifizieren. Da die Nachrichten miteinander verbunden sind, muss sie auch so zusammengesetzt werden, dass sie zu einer natürlichen Fehlermeldung werden.

Funktion 4 func Ursache (Fehler) Fehler

Wird verwendet, um die erste Fehlermeldung aus dem umschlossenen Fehler abzurufen. ** Sehr nützlich bei der Identifizierung der Ursache des ersten Fehlers. ** ** **

err := errors.New("repository err")
err = errors.Wrap(err, "service err")
err = errors.Wrap(err, "usecase err")
fmt.Println(errors.Cause(err))
// repository err

Ich suche die beste Fehlerbehandlung

Hier sind drei Methoden zur Fehlerbehandlung. Schauen wir uns nacheinander an, was das Problem ist und wie wir es lösen können.

Zusammenfassend denke ich, dass die beste Methode ** Beurteilung unter Verwendung der Methode 3-Schnittstelle ** ist. (Ich würde es begrüßen, wenn Sie in den Kommentaren darauf hinweisen könnten, ob es so etwas gibt!)

Methode 1 Beurteilung nach Fehlerwert

Code

var (
	//Definieren Sie mögliche Fehler
	ErrHoge = errors.New("this is error hoge")
	ErrFuga = errors.New("this is error fuga")
)

func Function(str string) error {
	//Gibt je nach Prozess unterschiedliche Fehler zurück
	if str == "hoge" {
		return ErrHoge
	}else if str == "fuga" {
		return ErrFuga
	}
	return nil
}


func main()  {
	err := Function("hoge")
	
	switch err {
	case ErrHoge:
		fmt.Println("hoge")
	case ErrFuga:
		fmt.Println("fuga")
	}
}

Zusammenfassung

Die switch-Anweisung bestimmt, ob der ** Rückgabewert ** der Funktion ErrHoge oder ErrFuga ist, und verteilt die Verarbeitung. ** Ich denke das ist ein schlechter Weg **. Die Probleme sind die folgenden drei Punkte.

Wenn die oben genannten Punkte Probleme verursachen, sollten Sie andere Methoden in Betracht ziehen.

Methode 2 Beurteilung nach Fehlertyp

Code

type Err struct {
	err error
}

func (e *Err) Error() string {
	return fmt.Sprint(e.err)
}

type ErrHoge struct {
	*Err
}
type ErrFuga struct {
	*Err
}

func Function(str string) error {
	//Gibt je nach Prozess unterschiedliche Fehler zurück
	if str == "hoge" {
		return ErrHoge{&Err{errors.New("this is error hoge")}}
	} else if str == "fuga" {
		return ErrFuga{&Err{errors.New("this is error fuga")}}
	}
	return nil
}

func main() {
	err := Function("hoge")

	switch err.(type) {
	case ErrHoge:
		fmt.Println("hoge")
	case ErrFuga:
		fmt.Println("fuga")
	}
}

Zusammenfassung

Die switch-Anweisung bestimmt, ob der ** Rückgabetyp ** der Funktion ErrHoge oder ErrFuga ist, und verteilt die Verarbeitung. Diese Methode ist auch nicht sehr gut, aber da die Wertbeurteilung in die Typbeurteilung geändert wird, Die folgenden Probleme von ** Beurteilung nach Fehlerwert ** wurden behoben.

Es gibt zwei verbleibende Probleme.

Methode 3 Beurteilung über die Schnittstelle

Code

type temporary interface {
	Temporary() bool
}

func IsTemporary(err error) bool {
	te, ok := errors.Cause(err).(temporary)
	return ok && te.Temporary()
}

type Err struct {
	s string
}

func (e *Err) Error() string { return e.s }

func (e *Err) Temporary() bool { return true }

func Function(str string) error {
	//Gibt je nach Prozess unterschiedliche Fehler zurück
	if str == "hoge" {
		return &Err{"this is error"}
	} else {
		errors.New("unerwarteter Fehler")
	}
	return nil
}

func main() {
	err := Function("hoge")

	if IsTemporary(err) {
		fmt.Println("Erwarteter Fehler:", err)
	} else {
		fmt.Println(err)
	}
}

Der Code ist etwas kompliziert, deshalb werde ich ihn erklären. Err implementiert die temporäre Schnittstelle. Daher ist es möglich, "diejenige einzugrenzen, die die temporäre Schnittstelle implementiert, und der Rückgabewert ist wahr" durch das Urteil "IsTemporary ()" der Verarbeitung auf der Benutzerseite.

Durch die Verwendung von error.cause, wie unten gezeigt, ist es auch dann möglich zu unterscheiden, ob der erste aufgetretene Fehler die temporäre Schnittstelle implementiert, selbst wenn der Fehler umbrochen wird.

//Überprüfen Sie, ob der zurückgegebene Fehler temporär implementiert wird
te, ok := err.(temporary)
//Überprüfen Sie, ob die erste Fehlerursache vorübergehend ist (← empfohlen).
te, ok := errors.Cause(err).(temporary)

Wenn Sie sich das Ergebnis von "IsTemporary (err)" ansehen, können Sie die Verarbeitung daher nach dem Fehler (Grundursache) sortieren, der zuerst aufgetreten ist.

Zusammenfassung

Diese Methode konnte die verbleibenden zwei Probleme mit ** Fehlertypbeurteilung ** lösen.

Wenn try-catch in Java golang ist, kann es anscheinend wie folgt implementiert werden.

java


public static void main(String[] args) {
	try {
        // ...
	} catch (ArithmeticException e) {
		// ...
	} catch (RuntimeException e) {
		// ...
	} catch (Exception e) {
		// ...
	}
}

golang


func main() {
	err := Function("//....")

	if IsArithmeticException(err) {
		// ...
	}
	if IsRuntimeException(err) {
		// ...
	}
	if IsException(err) {
		// ...
	}
	// ...
}

Schließlich

Ich habe drei Fehlerbehandlungen in Golang erklärt. Durch eine Beurteilung unter Verwendung der Schnittstelle von Methode 3 scheint es, dass die Verarbeitung nach der Art des Fehlers mit den geringsten Problemen unterteilt werden kann.

Ich lerne noch, daher würde ich mich freuen, wenn Sie mir in den Kommentaren mitteilen könnten, ob es andere Möglichkeiten gibt, mit Fehlern umzugehen.

Dieser Artikel war sehr hilfreich. https://dave.cheney.net/tag/error-handling

Nachtrag

・ 10.11.2018 "Die Struktur muss nach außen freigelegt werden" Diese Beschreibung wurde gelöscht. Indem die Struktur nicht nach außen ausgesetzt wird, kann eine Beurteilung nach Fehlertyp verhindert werden. Dies liegt daran, dass das Erstellen einer privaten Struktur das Problem verursacht, dass der Wert des Felds nicht von außen referenziert werden kann.

Recommended Posts

[Golang-Fehlerbehandlung] Der beste Weg, die Verarbeitung nach der Art des Fehlers aufzuteilen
Eine einfache Möglichkeit, die Verarbeitungsgeschwindigkeit einer von Linux erkannten Festplatte zu messen
Einführung in das maschinelle Lernen ~ Zeigen wir die Tabelle der K-Methode für den nächsten Nachbarn ~ (+ Fehlerbehandlung)
Einfache Möglichkeit, die Quelle der Python-Module zu überprüfen
Versuchen Sie, den Inhalt von Word mit Golang zu erhalten
BGM wird automatisch entsprechend dem Inhalt der Konversation ausgewählt
Ändern Sie den Einstellungswert von settings.py entsprechend der Entwicklungsumgebung
So erhöhen Sie die Verarbeitungsgeschwindigkeit der Erfassung der Scheitelpunktposition
Fehlerbehandlung nach dem Stoppen des Downloads der gelernten Daten von VGG16
Ändern Sie die Lautstärke von Pepper entsprechend der Umgebung (Ton).
Punkt entsprechend dem Bild
Berücksichtigen Sie die Verarbeitungsgeschwindigkeit, um den Bildpuffer mit numpy.ndarray zu verschieben