Go
Foutafhandeling
Zoeken…
Invoering
In Go worden onverwachte situaties behandeld met behulp van fouten , geen uitzonderingen. Deze benadering lijkt meer op die van C, met behulp van errno, dan op die van Java of andere objectgeoriënteerde talen, met hun try / catch-blokken. Een fout is echter geen geheel getal maar een interface.
Een functie die mogelijk mislukt, retourneert meestal een fout als de laatste retourwaarde. Als deze fout niet nul is , is er iets misgegaan en moet de beller van de functie dienovereenkomstig actie ondernemen.
Opmerkingen
Merk op hoe in Go u niet een fout te verhogen. In plaats daarvan retourneert u een fout in geval van mislukking.
Als een functie kan mislukken, is de laatst geretourneerde waarde meestal een error
.
// This method doesn't fail
func DoSomethingSafe() {
}
// This method can fail
func DoSomething() (error) {
}
// This method can fail and, when it succeeds,
// it returns a string.
func DoAndReturnSomething() (string, error) {
}
Een foutwaarde maken
De eenvoudigste manier om een fout te maken is door het errors
te gebruiken.
errors.New("this is an error")
Als u extra informatie aan een fout wilt toevoegen, biedt het fmt
pakket ook een handige methode voor het maken van fouten:
var f float64
fmt.Errorf("error with some additional information: %g", f)
Hier is een volledig voorbeeld, waarbij de fout wordt geretourneerd door een functie:
package main
import (
"errors"
"fmt"
)
var ErrThreeNotFound = errors.New("error 3 is not found")
func main() {
fmt.Println(DoSomething(1)) // succeeds! returns nil
fmt.Println(DoSomething(2)) // returns a specific error message
fmt.Println(DoSomething(3)) // returns an error variable
fmt.Println(DoSomething(4)) // returns a simple error message
}
func DoSomething(someID int) error {
switch someID {
case 3:
return ErrThreeNotFound
case 2:
return fmt.Errorf("this is an error with extra info: %d", someID)
case 1:
return nil
}
return errors.New("this is an error")
}
Een aangepast fouttype maken
In Go wordt een fout weergegeven door elke waarde die zichzelf als tekenreeks kan beschrijven. Elk type dat de ingebouwde error
implementeert, is een fout.
// The error interface is represented by a single
// Error() method, that returns a string representation of the error
type error interface {
Error() string
}
In het volgende voorbeeld wordt getoond hoe u een nieuw fouttype definieert met een letterlijke samengestelde tekenreeks.
// Define AuthorizationError as composite literal
type AuthorizationError string
// Implement the error interface
// In this case, I simply return the underlying string
func (e AuthorizationError) Error() string {
return string(e)
}
Ik kan nu mijn aangepaste fouttype als fout gebruiken:
package main
import (
"fmt"
)
// Define AuthorizationError as composite literal
type AuthorizationError string
// Implement the error interface
// In this case, I simply return the underlying string
func (e AuthorizationError) Error() string {
return string(e)
}
func main() {
fmt.Println(DoSomething(1)) // succeeds! returns nil
fmt.Println(DoSomething(2)) // returns an error message
}
func DoSomething(someID int) error {
if someID != 1 {
return AuthorizationError("Action not allowed!")
}
// do something here
// return a nil error if the execution succeeded
return nil
}
Retourneert een fout
In Ga je niet een fout te verhogen. In plaats daarvan retourneert u een error
in geval van een storing.
// This method can fail
func DoSomething() error {
// functionThatReportsOK is a side-effecting function that reports its
// state as a boolean. NOTE: this is not a good practice, so this example
// turns the boolean value into an error. Normally, you'd rewrite this
// function if it is under your control.
if ok := functionThatReportsOK(); !ok {
return errors.New("functionThatReportsSuccess returned a non-ok state")
}
// The method succeeded. You still have to return an error
// to properly obey to the method signature.
// But in this case you return a nil error.
return nil
}
Als de methode meerdere waarden retourneert (en de uitvoering kan mislukken), is de standaardconventie dat de fout als laatste argument wordt geretourneerd.
// This method can fail and, when it succeeds,
// it returns a string.
func DoAndReturnSomething() (string, error) {
if os.Getenv("ERROR") == "1" {
return "", errors.New("The method failed")
}
s := "Success!"
// The method succeeded.
return s, nil
}
result, err := DoAndReturnSomething()
if err != nil {
panic(err)
}
Verwerking van een fout
In Go kunnen fouten worden geretourneerd vanuit een functieaanroep. De conventie is dat als een methode kan mislukken, het laatst geretourneerde argument een error
.
func DoAndReturnSomething() (string, error) {
if os.Getenv("ERROR") == "1" {
return "", errors.New("The method failed")
}
// The method succeeded.
return "Success!", nil
}
U gebruikt meerdere variabele toewijzingen om te controleren of de methode is mislukt.
result, err := DoAndReturnSomething()
if err != nil {
panic(err)
}
// This is executed only if the method didn't return an error
fmt.Println(result)
Als u niet geïnteresseerd bent in de fout, kunt u deze gewoon negeren door deze toe te wijzen aan _
.
result, _ := DoAndReturnSomething()
fmt.Println(result)
Natuurlijk kan het negeren van een fout ernstige gevolgen hebben. Daarom wordt dit over het algemeen niet aanbevolen.
Als u meerdere methodeaanroepen hebt en een of meer methoden in de keten een fout kunnen retourneren, moet u de fout doorgeven naar het eerste niveau dat het aankan.
func Foo() error {
return errors.New("I failed!")
}
func Bar() (string, error) {
err := Foo()
if err != nil {
return "", err
}
return "I succeeded", nil
}
func Baz() (string, string, error) {
res, err := Bar()
if err != nil {
return "", "", err
}
return "Foo", "Bar", nil
}
Herstellen van paniek
Een veel voorkomende fout is om een segment te declareren en er indexen om aan te vragen zonder het te initialiseren, wat leidt tot een paniek "index buiten bereik". De volgende code legt uit hoe u kunt herstellen van de paniek zonder het programma te verlaten, wat normaal is voor een paniek. In de meeste situaties is het retourneren van een fout op deze manier in plaats van het programma in paniek te verlaten alleen nuttig voor ontwikkelings- of testdoeleinden.
type Foo struct {
Is []int
}
func main() {
fp := &Foo{}
if err := fp.Panic(); err != nil {
fmt.Printf("Error: %v", err)
}
fmt.Println("ok")
}
func (fp *Foo) Panic() (err error) {
defer PanicRecovery(&err)
fp.Is[0] = 5
return nil
}
func PanicRecovery(err *error) {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
//fmt.Println("Panicing")
//panic(r)
*err = r.(error)
} else {
*err = r.(error)
}
}
}
Het gebruik van een afzonderlijke functie (in plaats van sluiting) maakt het mogelijk dezelfde functie opnieuw te gebruiken in andere paniekgevoelige functies.