Gå til bedste praksis - Fejlhåndtering

Dette er den første artikel i en række lektioner, jeg har lært i de par år, jeg har arbejdet med Go i produktionen. Vi kører en lang række Go-tjenester i produktion hos Saltside Technologies (psst, jeg ansætter flere positioner i Bangalore til Saltside), og jeg driver også min egen virksomhed, hvor Go er en integreret del.

Vi vil dække en bred vifte af emner, store og små.

Det første emne, jeg ønskede at dække i denne serie, er fejlhåndtering. Det skaber ofte forvirring og irritation for nye Go-udviklere.

Noget baggrund - Fejlgrænsefladen

Bare så vi er på den samme side. Som du måske ved, er en fejl i Go simpelthen alt, hvad der implementerer fejlgrænsefladen. Sådan ser grænsefladedefinitionen ud:

type fejlgrænseflade {
    Fejl () streng
}

Så alt, hvad der implementerer strenge-metoden Error (), kan bruges som en fejl.

Kontroller for fejl

Brug af fejlstrukturer og typekontrol

Da jeg begyndte at skrive Go foretog jeg ofte streng sammenligninger af fejlmeddelelser for at se, hvad fejltypen var (ja, pinligt at tænke på, men sommetider er du nødt til at se tilbage for at gå fremad).

En bedre metode er at bruge fejltyper. Så du kan (selvfølgelig) oprette strukturer, der implementerer fejlgrænsefladen og derefter udføre sammenligning i en switch-sætning.

Her er et eksempel på en fejlimplementering.

type ErrZeroDivision struct {
    beskedstreng
}
func NewErrZeroDivision (meddelelsesstreng) * ErrZeroDivision {
    retur & ErrZeroDivision {
        besked: besked,
    }
}
func (e * ErrZeroDivision) Fejl () streng {
    retur e.message
}

Nu kan denne fejl bruges på denne måde.

func main () {
    resultat, fejl: = opdele (1,0, 0,0)
    hvis fejlagtigt! = nul {
        skifte fejl. (type) {
        sag * ErrZeroDivision:
            fmt.Println (err.Error ())
        Standard:
            fmt.Println ("Hvad h * er lige sket?")
        }
    }
    fmt.Println (resultat)
}
func divide (a, b float64) (float64, fejl) {
    hvis b == 0,0 {
        returnere 0,0, NewErrZeroDivision ("Kan ikke divideres med nul")
    }
    returner a / b, nul
}

Her er linket Go Play til det fulde eksempel. Bemærk omskifteren err. (Type) mønster, som gør det muligt at tjekke for forskellige fejltyper snarere end noget andet (som streng sammenligning eller noget lignende).

Brug af fejlpakken og direkte sammenligning

Ovenstående fremgangsmåde kan alternativt håndteres ved hjælp af fejlpakken. Denne tilgang anbefales til fejlkontrol i pakken, hvor du har brug for en hurtig fejlrepræsentation.

var errNotFound = fejl.Nyt ("Varen er ikke fundet")
func main () {
    err: = getItem (123) // Dette ville kaste errNotFound
    hvis fejlagtigt! = nul {
        skifte fejl {
        sag errNotFound:
            log.Println ("Den anmodede vare ikke fundet")
        Standard:
            log.Println ("Ukendt fejl opstod")
        }
    }
}

Denne tilgang er mindre god, når du har brug for mere komplekse fejlobjekter med f.eks. fejlkoder osv. I dette tilfælde skal du oprette din egen type, der implementerer fejlgrænsefladen.

Umiddelbar fejlhåndtering

Nogle gange støder jeg på kode som nedenunder (men som regel med mere fluff omkring ..):

func eksempel1 () fejl {
    err: = call1 ()
    returner err
}

Pointen her er, at fejlen ikke håndteres med det samme. Dette er en skrøbelig tilgang, da nogen kan indsætte kode mellem err: = call1 () og returfejlen, hvilket ville bryde hensigten, da det muligvis skygger for den første fejl. To alternative fremgangsmåder:

// Skjul returretningen og fejlen.
func eksempel2 () fejl {
    returner opkald1 ()
}
// Gør eksplicit fejlhåndtering lige efter opkaldet.
func example3 () fejl {
    err: = call1 ()
    hvis fejlagtigt! = nul {
        returner err
    }
    returnere nul
}

Begge ovenstående fremgangsmåder er fine med mig. De opnår den samme ting, som er; Hvis nogen har brug for at tilføje noget efter call1 (), er de nødt til at tage sig af fejlhåndteringen.

Det er alt for i dag

Hold øje med den næste artikel om Go Best Practices. Gå stærk :).

func main () {
    err: = readArticle ("Gå bedste praksis - Fejlhåndtering")
    hvis fejlagtigt! = nul {
        ping ( "@ sebdah")
    }
}