Go'da hataları işlemeyi öğrenin

Tamamlandı

Programlarınızı yazarken, programlarınızın başarısız olmasının çeşitli yollarını göz önünde bulundurmanız ve hataları yönetmeniz gerekir. Kullanıcılarınızın uzun ve kafa karıştırıcı bir yığın izleme hatası görmesi gerekmez. Neyin yanlış gittiği hakkında anlamlı bilgiler görmeleri daha iyidir. Gördüğünüz gibi, Go'nun programlarınızdaki özel durumları veya beklenmeyen davranışları yönetmek için ve recover gibi panic yerleşik işlevleri vardır. Ancak hatalar, programlarınızın işlenecek şekilde derlenmesi gereken bilinen hatalardır.

Go'nun hata işleme yaklaşımı yalnızca bir ve deyiminin gerekli olduğu bir if return denetim akışı mekanizmasıdır. Örneğin, bir nesneden bilgi almak için bir employee işlevi çağırırken çalışanın var olup olmadığını bilmek isteyebilirsiniz. Go'nun bu tür bir beklenen hatayı işlemeye yönelik düşünceli yolu şöyle görünür:

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

İşlevin yapıyı getInformation employee ve ikinci değer olarak bir hatayı nasıl döndürdüğüne dikkat edin. Hata olabilir nil. Hata ise nil, bu başarı anlamına gelir. nilDeğilse, bu başarısızlık anlamına gelir. Hata olmayannil bir hata, yazdırabileceğiniz veya tercihen günlüğe kaydedebileceğiniz bir hata iletisiyle birlikte gelir. Go'da hataları bu şekilde işlersiniz. Sonraki bölümde birkaç stratejiyi daha ele alacağız.

Go'da hata işlemenin, bir hatayı nasıl raporladığınıza ve işlediğinize daha fazla dikkat etmenizi gerektirdiğini fark edeceksiniz. İşte asıl mesele de bu. Go'nun hata işleme yaklaşımını daha iyi anlamanıza yardımcı olacak diğer örneklere göz atalım.

Çeşitli hata işleme stratejileri uygulamak için yapılar için kullandığımız kod parçacığını kullanacağız:

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
}

Bundan sonra, hataların getInformationnasıl işleneceğini göstermek için , apiCallEmployeeve main işlevlerini değiştirmeye odaklanacağız.

Hata işleme stratejileri

bir işlev hata döndürdüğünde genellikle son dönüş değeri olur. Önceki bölümde gördüğünüz gibi bir hata olup olmadığını denetlemek ve bu hatayı işlemek çağıranın sorumluluğundadır. Bu nedenle yaygın bir strateji, bir alt yordamdaki hatayı yaymak için bu düzeni kullanmaya devam etmektir. Örneğin, bir alt yordam (önceki örnekte olduğu gibi getInformation ) aşağıdaki gibi başka bir şey yapmadan çağırana hata döndürebilir:

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
}

Hatayı yaymadan önce daha fazla bilgi de eklemek isteyebilirsiniz. Bu amaçla, daha önce gördüğümüze benzer ancak bir hata döndüren işlevini kullanabilirsiniz fmt.Errorf() . Örneğin, hataya daha fazla bağlam ekleyebilir ve yine de aşağıdaki gibi özgün hatayı döndürebilirsiniz:

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
}

Bir diğer strateji de hatalar geçici olduğunda yeniden deneme mantığını çalıştırmaktır. Örneğin, bir işlevi üç kez çağırmak ve aşağıdaki gibi iki saniye beklemek için yeniden deneme ilkesi kullanabilirsiniz:

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")
}

Son olarak, hataları konsola yazdırmak yerine hataları günlüğe kaydedebilir ve uygulama ayrıntılarını son kullanıcılardan gizleyebilirsiniz. Sonraki modülde günlüğe kaydetmeyi ele alacağız. Şimdilik özel hataları nasıl oluşturabileceğinize ve kullanabileceğinize bakalım.

Yeniden kullanılabilir hatalar oluşturma

Bazen hata iletilerinin sayısı artar ve düzeni korumak istersiniz. Veya yeniden kullanmak istediğiniz yaygın hata iletileri için bir kitaplık oluşturmak isteyebilirsiniz. Go'da, hata oluşturmak ve bunları aşağıdaki gibi birkaç bölümde yeniden kullanmak için işlevini kullanabilirsiniz errors.New() :

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
}

İşlevin getInformation kodu daha iyi görünür ve hata iletisini değiştirmeniz gerekirse, bunu tek bir yerde yaparsınız. Ayrıca, kuralın hata değişkenleri için ön ek eklemek Err olduğuna dikkat edin.

Son olarak, bir hata değişkeniniz olduğunda, çağıran işlevindeki bir hatayı işlerken daha belirgin olabilirsiniz. işlevi, errors.Is() aşağıdaki gibi, almakta olduğunuz hata türünü karşılaştırmanıza olanak tanır:

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

Go'daki hataları işlerken göz önünde bulundurmanız gereken bazı önerilen uygulamalar şunlardır:

  • Hataları beklemeseniz bile her zaman denetleyin. Ardından, gereksiz bilgilerin son kullanıcılara açık olmasını önlemek için bunları düzgün bir şekilde işleyin.
  • Hatanın kaynağını bilmeniz için hata iletisine bir ön ek ekleyin. Örneğin, paketin ve işlevin adını ekleyebilirsiniz.
  • Mümkün olduğunca yeniden kullanılabilir hata değişkenleri oluşturun.
  • Geri dönen hataları kullanma ile panikleme arasındaki farkı anlayın. Yapabileceğin başka bir şey olmadığında panik yap. Örneğin, bir bağımlılık hazır değilse, programın çalışması mantıklı değildir (varsayılan bir davranış çalıştırmak istemiyorsanız).
  • Mümkün olduğunca çok ayrıntı içeren hataları günlüğe kaydetme (sonraki bölümde nasıl yapılacağını ele alacağız) ve son kullanıcının anlayabileceği hataları yazdırın.