Menu

Golang Hatalar: Sarmalama, errors.Is, errors.As ve Özel Tipler

Sentinel hatalar ve özel hata tipleri tanımlayın, hataları %w ile sarmalayın, errors.Is ve errors.As ile kontrol edin, errors.Join ile birkaçını birleştirin ve gerektiğinde Unwrap ve Is metotları yazın.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Üç tür hata

Go kodu en basitten en zengine üç biçimde hata kullanır:

  1. Geçici bir hata: yerinde oluşturulan errors.New("...") ya da fmt.Errorf("..."). Çağıranlar yalnızca mesajı okuyabilir.
  2. Bir sentinel hata: io.EOF gibi paket seviyesinde bir değişken. Çağıranlar onu errors.Is ile test edebilir.
  3. Bir hata tipi: alanlar taşıyan, Error() metodu olan bir struct. Çağıranlar onu errors.As ile çıkarıp alanlarını okuyabilir.

Çağıranların ihtiyaç duyduğu şeyi yapmasına izin veren en basit olanı seçin.

Sentinel hatalar

Sentinel, bir kez tanımlanan ve kimliğine göre karşılaştırılan bir hata değeridir. Adlar geleneksel olarak Err ile başlar.

Çıktı:

mug bought
cap is out of stock, notify me later
buy "hat": not found

Aynı metinli iki errors.New çağrısı farklı hatalar üretir: errors.New("x") == errors.New("x") sonucu false'tur. Bir sentinel'in tek bir paylaşılan değişken olması gerekmesinin nedeni budur.

Sentinel'ler paketinizin API'sinin bir parçası haline gelir. Çağıranlar ErrNotFound'u kontrol etmeye başladığında onları bozmadan onu döndürmeyi bırakamazsınız. Yalnızca çağıranların gerçekten dallanması gerekenleri dışa açın.

Özel hata tipleri

Çağıranın ayrıntılara (hangi alan, hangi durum kodu, hangi yeniden deneme gecikmesi) ihtiyacı olduğunda bir tip tanımlayın.

Çıktı:

register: age: must be between 0 and 150
bad field: age

Metodun pointer alıcısı var ve fonksiyon &ValidationError{...} döndürüyor, bu yüzden errors.As'in hedefi bir *ValidationError'dır ve onun adresini (&ve, bir **ValidationError) aktarırsınız. Bu seviyeyi karıştırmak klasik errors.As hatasıdır: değer alıcıyla ValidationError{...} döndürür ve var ve ValidationError tanımlardınız. go vet en yaygın kaymayı, &ve yerine ve aktarmayı yakalar: second argument to errors.As must be a non-nil pointer to either a type that implements error, or to any interface type.

%w ile sarmalamak

%w ile fmt.Errorf, sarmaladığı hatayı hatırlayan bir hata döndürür. Her katman bağlam ekler ve zinciri bozmadan tutar.

Çıktı:

start: connect db: timeout
  *fmt.wrapError: start: connect db: timeout
  *fmt.wrapError: connect db: timeout
  *errors.errorString: timeout
true
false

%v ile mesaj aynıdır ama zincir kesilir, bu yüzden errors.Is false döndürür. Çağıranların nedeni görebilmesi gerekiyorsa %w, neden onların bağımlı olmasını istemediğiniz bir uygulama ayrıntısıysa %v seçin.

Go 1.20'den beri tek bir çağrı birkaç hatayı sarmalayabilir: fmt.Errorf("%w; %w", err1, err2). errors.Is bu durumda ikisinden biriyle eşleşir.

errors.Join: aynı anda birkaç hata

Doğrulama ve temizlik çoğu zaman birden fazla hata üretir. errors.Join (Go 1.20) onları bir araya getirir.

Çıktı:

name: required
email: required
age: negative
---
true
true

Her argüman nil olduğunda errors.Join nil döndürür, bu yüzden yukarıdaki fonksiyonun "hata yok" için özel bir duruma ihtiyacı yoktur.

Unwrap ve Is metotları

errors.Is ve errors.As, sarmalanmış hataları bir Unwrap metodunu çağırarak bulur. Bir neden tutan özel bir tip onu dışa sunmalıdır:

Birkaç hatayı sarmalayan bir tip bunun yerine Unwrap() []error gerçekleştirir.

Bir tip eşitliğe kendisi karar vermek için Is(target error) bool de tanımlayabilir; örneğin aynı durum koduna sahip herhangi bir *HTTPError ile eşleşmek için. Buna nadiren ihtiyaç duyarsınız; bir sentinel'i sarmalayıp Unwrap'tan döndürmek genellikle işi görür.

Tipli nil tuzağı

Bir hata değişkenini asla somut tipinizle tanımlayıp error üzerinden döndürmeyin:

func check() error {
	var err *ValidationError // nil pointer
	// ... no problem found
	return err // non-nil error! Its type is *ValidationError
}

Çağıranın if err != nil'i true olur, çünkü tipli nil bir pointer tutan bir interface nil değildir. Başarıda düz bir nil döndürün ve yerel hata değişkenlerini error tipinde tutun. Nedenini interface'ler sayfası açıklıyor.

Hangi türü seçmeli

Çağıranların yapması gerekenSağlayın
yalnızca başarısızlığı loglamak ya da göstermekfmt.Errorf("...: %w", err)
belirli bir duruma göre dallanmakbir sentinel var ErrX = errors.New(...)
başarısızlıkla ilgili ayrıntıları okumakalanları olan bir hata tipi
birkaç bağımsız başarısızlığı görmekerrors.Join

Sık yapılan hatalar

  • Sarmalanmış hataları == ile karşılaştırmak. errors.Is kullanın.
  • errors.As'e pointer olmayan bir şey aktarmak. Hedef tipte bir değişkene pointer ister.
  • Bir fonksiyonun içinde "sentinel" oluşturmak. return errors.New("not found") her çağrıda yeni bir değer oluşturur; çağıranlar onunla karşılaştırma yapamaz.
  • Her hatayı dışa açmak. Dışa açılan her sentinel ya da tip bir API sözüdür.
  • err.Error()'a göre eşleştirmek. String'ler insanlar içindir.

Sıkça Sorulan Sorular

Go'da özel bir hata nasıl oluşturulur?

Sabit bir durum için paket seviyesinde bir sentinel tanımlayın: var ErrNotFound = errors.New("not found"). Veri taşıyan bir hata için Error() string metodu olan bir tip tanımlayın: type ValidationError struct { Field string } ve func (e *ValidationError) Error() string { return e.Field + " is invalid" }.

Go'da bir hata nasıl sarmalanır?

%w verb'ü ile fmt.Errorf kullanın: return fmt.Errorf("load user %d: %w", id, err). Yeni hatanın mesajı eskisini içerir ve errors.Unwrap, errors.Is ve errors.As orijinale ulaşabilir. Go 1.20'den beri tek bir Errorf çağrısı birkaç %w verb'ü ile birkaç hatayı sarmalayabilir.

errors.Is ile errors.As arasındaki fark nedir?

errors.Is(err, target), io.EOF gibi sentinel'ler için "bu belirli hata değeri zincirin herhangi bir yerinde var mı" sorusunu yanıtlar. errors.As(err, &target) ise "zincirde bu tipte bir hata var mı" sorusunu yanıtlar ve varsa alanlarını okuyabilmeniz için onu target içine saklar.

errors.Join ne yapar?

errors.Join(errs...) (Go 1.20) birkaç hatayı tek bir hatada birleştirir. Mesajı, satır sonlarıyla ayrılmış tek tek mesajlardır; nil hatalar atılır ve hepsi nil ise nil döndürür. Birleştirilen hatalardan herhangi biri eşleşirse errors.Is ve errors.As eşleşir.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA