Naučte se zpracovávat chyby v Go.

Dokončeno

Při psaní programů je potřeba zvážit různé způsoby selhání programů a potřebujete spravovat selhání. Uživatelé nemusí vidět dlouhou a matoucí chybu trasování zásobníku. Lepší je, když uvidí smysluplné informace o tom, co se nepovedlo. Jak jste viděli, Go má integrované funkce, jako je panic správa recover výjimek nebo neočekávaného chování v programech. Ale chyby jsou známé chyby, které by měly být vytvořeny pro zpracování vašich programů.

Přístup go ke zpracování chyb je jednoduše mechanismus toku řízení, ve kterém jsou potřeba jenom if příkazy a return příkazy. Když například voláte funkci pro získání informací z objektu employee , můžete chtít zjistit, jestli zaměstnanec existuje. Názorný způsob zpracování takové očekávané chyby by vypadal takto:

employee, err := getInformation(1000)
if err != nil {
    // Something is wrong. Do something.
}

Všimněte si, jak getInformation funkce vrací employee strukturu a také chybu jako druhou hodnotu. Chyba může být nil. Pokud se niljedná o chybu, znamená to úspěch. Pokud tomu tak není nil, znamená to selhání. Chyba,nil která není chybná, obsahuje chybovou zprávu, kterou můžete vytisknout nebo nejlépe protokolovat. Tímto způsobem zpracováváte chyby v Go. V další části se budeme zabývat několika dalšími strategiemi.

Pravděpodobně si všimnete, že zpracování chyb v Go vyžaduje, abyste měli větší pozornost na to, jak hlásíte a zpracováváte chybu. To je přesně ten bod. Podívejme se na některé další příklady, které vám pomůžou lépe porozumět přístupu Go ke zpracování chyb.

K procvičení různých strategií zpracování chyb použijeme fragment kódu, který jsme použili pro struktury:

package main

import (
    "fmt"
    "os"
)

type Employee struct {
    ID        int
    FirstName string
    LastName  string
    Address   string
}

func main() {
    employee, err := getInformation(1001)
    if err != nil {
        // Something is wrong. Do something.
    } else {
        fmt.Print(employee)
    }
}

func getInformation(id int) (*Employee, error) {
    employee, err := apiCallEmployee(1000)
    return employee, err
}

func apiCallEmployee(id int) (*Employee, error) {
    employee := Employee{LastName: "Doe", FirstName: "John"}
    return &employee, nil
}

Odsud se zaměříme na úpravu getInformationapiCallEmployee, a main funkcí, abychom ukázali, jak zpracovávat chyby.

Strategie zpracování chyb

Když funkce vrátí chybu, obvykle se jedná o poslední návratovou hodnotu. Volající zodpovídá za kontrolu, jestli existuje chyba, a zpracovat ji, jak jste viděli v předchozí části. Běžnou strategií je pokračovat v používání takového vzoru k šíření chyby v podprogramu. Například podprogram (například getInformation v předchozím příkladu) by volajícímu mohl vrátit chybu, aniž by udělal něco jiného, například takto:

func getInformation(id int) (*Employee, error) {
    employee, err := apiCallEmployee(1000)
    if err != nil {
        return nil, err // Simply return the error to the caller.
    }
    return employee, nil
}

Před rozšířením chyby můžete také zahrnout další informace. Pro tento účel byste mohli použít fmt.Errorf() funkci, která je podobná tomu, co jsme viděli dříve, ale vrátí chybu. Můžete například k chybě přidat další kontext a přesto vrátit původní chybu, například takto:

func getInformation(id int) (*Employee, error) {
    employee, err := apiCallEmployee(1000)
    if err != nil {
        return nil, fmt.Errorf("Got an error when getting the employee information: %v", err)
    }
    return employee, nil
}

Další strategií je spustit logiku opakování, pokud jsou chyby přechodné. Můžete například použít zásadu opakování k volání funkce třikrát a počkat na dvě sekundy, například takto:

func getInformation(id int) (*Employee, error) {
    for tries := 0; tries < 3; tries++ {
        employee, err := apiCallEmployee(1000)
        if err == nil {
            return employee, nil
        }

        fmt.Println("Server is not responding, retrying ...")
        time.Sleep(time.Second * 2)
    }

    return nil, fmt.Errorf("server has failed to respond to get the employee information")
}

Nakonec místo tisku chyb do konzoly můžete protokolovat chyby a skrýt všechny podrobnosti implementace od koncových uživatelů. Budeme se zabývat protokolováním v dalším modulu. Prozatím se podíváme na to, jak můžete vytvářet a používat vlastní chyby.

Vytváření opakovaně použitelných chyb

Někdy se počet chybových zpráv zvyšuje a chcete zachovat pořadí. Nebo můžete chtít vytvořit knihovnu pro běžné chybové zprávy, které chcete znovu použít. V go můžete pomocí errors.New() funkce vytvářet chyby a opakovaně je používat v několika částech, například takto:

var ErrNotFound = errors.New("Employee not found!")

func getInformation(id int) (*Employee, error) {
    if id != 1001 {
        return nil, ErrNotFound
    }

    employee := Employee{LastName: "Doe", FirstName: "John"}
    return &employee, nil
}

Kód funkce getInformation vypadá lépe a pokud potřebujete změnit chybovou zprávu, uděláte to jenom na jednom místě. Všimněte si také, že konvence zahrnuje předponu Err pro chybové proměnné.

A konečně, pokud máte chybovou proměnnou, můžete být konkrétnější při zpracování chyby ve funkci volajícího. Funkce errors.Is() umožňuje porovnat typ chyby, která se vám zobrazuje, například takto:

employee, err := getInformation(1000)
if errors.Is(err, ErrNotFound) {
    fmt.Printf("NOT FOUND: %v\n", err)
} else {
    fmt.Print(employee)
}

Při zpracování chyb v Go je několik doporučených postupů, které je potřeba vzít v úvahu:

  • Vždy zkontrolujte chyby, i když je neočekáváte. Pak je zpracujte správně, abyste koncovým uživatelům zabránili vystavovat zbytečné informace.
  • Do chybové zprávy zahrňte předponu, abyste věděli o původu chyby. Můžete například zahrnout název balíčku a funkce.
  • Vytvořte opakovaně použitelné chybové proměnné tak, jak můžete.
  • Seznamte se s rozdílem mezi používáním vrácených chyb a panickingu. Panice, když není nic jiného, co bys mohl udělat. Pokud například závislost není připravená, nemá smysl, aby program fungoval (pokud nechcete spustit výchozí chování).
  • Chyby protokolu s co nejvíce podrobnostmi (probereme to v další části) a vypíšeme chyby, kterým koncový uživatel rozumí.