ProgramlamaGo Geliştiricisi

Go'daki hatalarla (errors) çalışma özellikleri nelerdir, hataları nasıl doğru şekilde oluşturmalı ve işlemeliyiz, ve kendi hata türlerimizi nasıl uygulamalıyız?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap

Go, başlangıçtan itibaren istisnalar yerine hataların açık bir şekilde döndürülmesi üzerine inşa edilmiştir. Bu, tahmin edilebilir bir kod geliştirmeye ve diğer dillerde (örneğin, Java veya C++) bulunan try/catch yapılarının getirdiği gizli tuzaklardan kaçınmaya yardımcı olur. Go'daki bir hata, Error() metodunu uygulayan bir arayüzdür ve bu da hem basit hem de içerik (context) ile paketlenmiş hataların oluşturulmasına olanak tanır.

Hataların yanlış işlenmesi (örneğin, bunları _ ile görmezden gelmek veya hata ayıklama için ek bilgiyle sarmalamamak) ya da hataların "büyülü" (magic) bir biçimde, error arayüzüne uymayacak şekilde oluşturulması sorunlara yol açar. Ayrıca, genel işlevlerden hataları döndürmeyi ve her çağrıda kontrol etmeyi de bilmek önemlidir.

Çözüm — standart yaklaşımları kullanmaktır:

  • Hata her zaman işlevin son değeri olarak döndürülmelidir.
  • Hataları oluşturmak için errors.New, fmt.Errorf kullanılmalıdır.
  • Özel hatalar oluşturmak için Error() metodunu uygulayan kendi türlerinizi oluşturun.
  • Karmaşık durumlar için, bağlamı kaybetmemek için hata sarmalayıcılar (errors.Wrap) kullanılmalıdır.

Kod örneği:

import ( "errors" "fmt" ) type NotFoundError struct { Resource string } func (e *NotFoundError) Error() string { return fmt.Sprintf("%s bulunamadı", e.Resource) } func GetUser(id int) (string, error) { if id != 1 { return "", &NotFoundError{"Kullanıcı"} } return "Steve", nil } func main() { user, err := GetUser(2) if err != nil { if nfe, ok := err.(*NotFoundError); ok { fmt.Println(nfe.Resource, "sorun") } else { fmt.Println("hata:", err) } } fmt.Println("kullanıcı:", user) }

Anahtar özellikler:

  • Hatalar her zaman açıkça, genellikle işlevin son argümanı olarak döndürülür.
  • Karmaşık hatalar için, error arayüzünü uygulayan kendi türlerinizi (struct) tanımlayabilirsiniz.
  • Hata sarmalamak ve stack trace'i korumak için "errors" paketini kullanabilirsiniz (Go 1.13+ için errors.Is ve errors.As desteklenmektedir).

Kandırmaca Soruları.

Error'ı işlerken, karşılaştırma yapmak için == mi yoksa özel yöntemleri mi kullanmak gerekir?

Her zaman errors.Is() kullanarak sarmalayıcı hatalar ile karşılaştırma yapmak daha iyidir, aksi takdirde == ile karşılaştırma, hata sarmalayıcıları olduğunda çalışmayabilir.

if errors.Is(err, os.ErrNotExist) { // dosyanın olmaması durumunda işleme }

Özel bir hata için tür yapısını uygulamak zorunlu mu, yoksa sadece errors.New("...") kullanmak yeterli mi?

Eğer sadece hata mesajına ihtiyacınız varsa, errors.New() yeterlidir. Eğer bağlamı (örneğin, kaynak adını) korumak önemliyse, Error() metodu olan bir struct belirlemek daha iyidir.

Başarılı bir işlev çağrısında hatayı nasıl doğru şekilde döndürmeliyim?

Başarı durumunda her zaman nil hata döndürmelisiniz.

return result, nil

Tipik Hatalar ve Anti-Desenler

  • Geri dönen hataların göz ardı edilmesi (işlemden atlanması veya _ ile geçiştirilmesi)
  • Hataların sadece == ile karşılaştırılması, iç içe geçmiş hatalar olmasına rağmen
  • Hatalar yerine sabitlenmiş dizgiler kullanılması
  • Hatalarda ek bağlamın olmaması

Gerçek Hayattan Bir Örnek

Olumsuz Durum

Bir geliştirici, açıklama olmadan hata döndüren bir işlev yazıyor (sadece errors.New("başarısız")). Logları analiz ederken sebep tespit edilemiyor.

Artılar:

  • Uygulama hızı

Eksiler:

  • Bilgi vermeyen hatalar
  • Hata ayıklama zorluğu

Olumlu Durum

Bir geliştirici, NotFoundError adlı özel bir hata türünü tanımlar ve onu ayrıntılı açıklama ile döndürür.

Artılar:

  • Logların filtrelemesi kolaydır
  • Hataların aranması ve işlenmesi kolaydır

Eksiler:

  • Ek yapıların açıklanması gerekliliği