Idite najbolje prakse - rukovanje pogreškama

Ovo je prvi članak u nizu lekcija koje sam naučio tijekom nekoliko godina koliko sam radio s proizvodnjom Go. Vodimo dobar broj Go usluga u proizvodnji u Saltside Technologies (psst, angažiram se za više pozicija u Bangaloreu za Saltside), a vodim i vlastiti posao u kojem je Go sastavni dio.

Obuhvatit ćemo širok raspon predmeta, velikih i malih.

Prvi predmet koji sam želio pokriti u ovoj seriji je postupanje s pogreškama. To često uzrokuje zbunjenost i neugodnost za nove programere Go.

Neka pozadina - sučelje pogreške

Samo što smo na istoj stranici. Kao što možda znate da je greška u Go-u jednostavno sve što implementira sučelje pogreške. Ovako izgleda definicija sučelja:

sučelje pogreške greške {
    Error () string
}

Dakle, sve što implementira string pogreške Error () može se koristiti kao greška.

Provjera za pogreške

Upotreba struktura grešaka i provjera tipa

Kad sam započeo pisati Go, često sam vršio stringove usporedbe poruka o pogreškama da bih vidio kakvu vrstu pogreške (da, sramotno je razmišljati, ali ponekad se trebate osvrnuti da krenete naprijed).

Bolji pristup je upotreba vrsta pogrešaka. Tako možete (naravno) stvoriti strukture koje implementiraju sučelje pogrešaka, a zatim upotrijebite usporedbu u naredbi switch.

Evo primjera implementacije pogreške

upišite ErrZeroDivision structure {
    niz poruka
}
func NewErrZeroDivision (niz poruka) * ErrZeroDivision {
    return & ErrZeroDivision {
        poruka: poruka,
    }
}
func (e * ErrZeroDivision) Error () string {
    vratiti e.message
}

Sada se ova greška može koristiti ovako.

func main () {
    rezultat, greška: = podjela (1,0, 0,0)
    ako griješi! = nula {
        prebacivanje pogreška (tip) {
        slučaj * ErrZeroDivision:
            fmt.Println (err.Error ())
        zadano:
            fmt.Println ("Što se h * upravo dogodilo?")
        }
    }
    fmt.Println (rezultat)
}
func podijeli (a, b float64) (float64, pogreška) {
    ako je b == 0,0 {
        povratak 0,0, NewErrZeroDivision ("Ne mogu se podijeliti na nulu")
    }
    vratiti a / b, nil
}

Evo poveznice Go Play za potpuni primjer. Uočite uzorak pogreške (tip) greške, koji omogućava provjeru postoje li različite vrste pogrešaka, a ne nešto drugo (poput usporedbe niza ili nečeg sličnog).

Korištenje paketa pogrešaka i izravna usporedba

Gornjim pristupom alternativno se može postupati korištenjem paketa grešaka. Ovaj se pristup preporučuje za provjeru pogreške unutar paketa gdje vam treba brzo predstavljanje pogreške.

var errNotFound = pogreške.New ("Stavka nije pronađena")
func main () {
    err: = getItem (123) // Ovo bi bacilo errNotFound
    ako griješi! = nula {
        prebacivanje pogreška {
        slučaj errNotFound:
            log.Println ("Tražena stavka nije pronađena")
        zadano:
            log.Println ("Nepoznata greška")
        }
    }
}

Ovaj je pristup manje dobar kada vam trebaju složeniji objekti o pogrešci s npr. kodovi pogrešaka itd. U tom slučaju trebali biste stvoriti vlastiti tip koji implementira sučelje pogreške.

Neposredno rukovanje pogreškama

Ponekad naiđem na kôd poput dolje (ali obično s više pahuljica oko):

func example1 () error {
    err: = call1 ()
    greška u vraćanju
}

Poanta je u tome da se greška ne rješava odmah. Ovo je krhki pristup jer netko može umetnuti kôd između err: = call1 () i povratne pogreške, što bi razbilo namjeru, jer to može zasjeniti prvu pogrešku. Dva alternativna pristupa:

// Sažmi povrat i pogrešku.
func example2 () error {
    uzvratni poziv1 ()
}
// Izričite rukovanje pogreškama odmah nakon poziva.
func example3 () error {
    err: = call1 ()
    ako griješi! = nula {
        greška u vraćanju
    }
    povratna nula
}

Oba gore navedena pristupa su u redu sa mnom. Oni postižu isto, a to je; ako netko mora nešto dodati nakon call1 (), mora se pobrinuti za postupanje s pogreškama.

To je sve za danas

Pratite sljedeći članak o Go Best Practices. Idi snažno :).

func main () {
    err: = readArticle ("Najbolje prakse - rukovanje pogreškama")
    ako griješi! = nula {
        ping ( "@ sebdah")
    }
}