errors.Is() ve errors.As()
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 56 / 107.
Hatalar sarmalandığında, err == ErrNotFound gibi basit eşitlik kontrolleri artık çalışmaz. errors paketi, sarmalanmış hata zincirlerini incelemek için iki fonksiyon sağlar: errors.Is() ve errors.As().
errors.Is() zincirdeki herhangi bir hatanın belirli bir sentinel hatasıyla eşleşip eşleşmediğini kontrol eder:
import "errors"
var ErrNotFound = errors.New("not found")
func FindUser(id int) error {
return fmt.Errorf("database lookup failed: %w", ErrNotFound)
}
err := FindUser(42)
if errors.Is(err, ErrNotFound) {
fmt.Println("User doesn't exist")
}Döndürülen hata sarmalanmış olsa bile, errors.Is() zinciri açar ve içinde ErrNotFound öğesini bulur.
errors.As(), zincirdeki herhangi bir hatanın belirli bir tür ile eşleşip eşleşmediğini kontrol eder ve onu ayıklar:
type ValidationError struct {
Field string
}
func (e *ValidationError) Error() string {
return "validation failed: " + e.Field
}
err := fmt.Errorf("request failed: %w", &ValidationError{Field: "email"})
var ve *ValidationError
if errors.As(err, &ve) {
fmt.Println("Invalid field:", ve.Field)
}Sentinel hatalarını kontrol ederken errors.Is(), özel bir hata türündeki alanlara erişmeniz gerektiğinde ise errors.As() kullanın. Her iki fonksiyon da tüm hata zincirini tarar; bu da onları sarmalanmış hataları düzgün bir şekilde yönetmek için vazgeçilmez kılar.
Görev
Kolayerrors.Is() ve errors.As() kullanarak sarmalanmış hata zincirlerini (wrapped error chains) düzgün bir şekilde nasıl inceleyeceğinizi gösteren bir dosya işleme sistemi oluşturalım. Farklı katmanlardan geçerken sarmalanan hatalar oluşturacak, ardından bu fonksiyonları kullanarak hataları tanımlayacak ve içlerinden bilgi çıkaracaksınız.
Kodunuzu iki dosya halinde düzenleyeceksiniz:
errors.go: Dosya sisteminiz için hata altyapısını tanımlayın.Bir sentinel hatası oluşturun:
"permission denied"mesajına sahipErrPermissionDenied
Özel bir hata türü oluşturun:
Filename(string) veOperation(string) alanlarına sahipFileErroryapısı (struct)Error()metodu şu sonucu döndürmelidir:[Operation] failed on file: [Filename]
Dosya işlemlerini simüle eden ve hataları sarmalayan iki fonksiyon uygulayın:
ReadFile(filename string) error- Eğer filename"secret.txt"ise,ErrPermissionDenieddöndürün. Eğer filename"missing.txt"ise, Operation değeri"read"olan ve verilen Filename'i içeren bir*FileErrordöndürün. Aksi takdirdenildöndürün.ProcessFile(filename string) error-ReadFilefonksiyonunu çağırır. Eğer bir hata dönerse, bunufmt.Errorfkullanarak"processing failed: %w"formatıyla sarmalayın. Aksi takdirdenildöndürün.
main.go: Girdiden bir dosya adı okuyun veProcessFilefonksiyonunu çağırın. Sarmalanmış hata zincirini incelemek içinerrors.Is()veerrors.As()kullanın ve içeride bulduğunuz şeye göre uygun mesajları yazdırın.
Aşağıdaki girdi sağlanacaktır:
- Satır 1: İşlenecek dosya adı
Hata zincirini inceleyerek sonucu yönetin:
- Eğer
errors.Is()zincirdeErrPermissionDeniedbulursa: tam hata mesajını yazdırın, ardından yeni bir satırdaAccess denied - check file permissionsyazdırın - Eğer
errors.As()zincirde bir*FileErrorbulursa: tam hata mesajını yazdırın, ardından yeni bir satırdaFile issue: [Filename] during [Operation]yazdırın - Eğer hata oluşmazsa:
File '[filename]' processed successfullyyazdırın
Örneğin, secret.txt verildiğinde çıktınız şöyle olmalıdır:
processing failed: permission denied
Access denied - check file permissionsVe missing.txt verildiğinde çıktınız şöyle olmalıdır:
processing failed: read failed on file: missing.txt
File issue: missing.txt during readVe data.txt verildiğinde çıktınız şöyle olmalıdır:
File 'data.txt' processed successfullyHatalar ProcessFile tarafından sarmalanmış olsa bile, errors.Is() ile orijinal sentinel hatasını nasıl tespit edebildiğinize ve errors.As() ile özel hata türünü nasıl çıkarabildiğinize dikkat edin. Bu fonksiyonlar, aradığınızı bulmak için tüm hata zinciri boyunca ilerler.
Kopya kağıdı
Hatalar sarmalandığında (wrapped), hata zincirini incelemek için errors paketindeki errors.Is() ve errors.As() fonksiyonlarını kullanın.
errors.Is(), zincirdeki herhangi bir hatanın belirli bir sentinel hata ile eşleşip eşleşmediğini kontrol eder:
import "errors"
var ErrNotFound = errors.New("not found")
err := fmt.Errorf("database lookup failed: %w", ErrNotFound)
if errors.Is(err, ErrNotFound) {
// ErrNotFound zincirde bulundu
}errors.As(), zincirdeki herhangi bir hatanın belirli bir tiple eşleşip eşleşmediğini kontrol eder ve onu dışarı çıkarır:
type ValidationError struct {
Field string
}
func (e *ValidationError) Error() string {
return "validation failed: " + e.Field
}
err := fmt.Errorf("request failed: %w", &ValidationError{Field: "email"})
var ve *ValidationError
if errors.As(err, &ve) {
// ve artık zincirdeki ValidationError'ı içeriyor
fmt.Println(ve.Field)
}Sentinel hatalar için errors.Is(), özel hata tiplerindeki alanlara erişmeniz gerektiğinde ise errors.As() kullanın. Her iki fonksiyon da tüm hata zinciri boyunca ilerler.
Kendin dene
package main
import (
"errors"
"fmt"
)
func main() {
// Dosya adını girdiden oku
var filename string
fmt.Scanln(&filename)
// ProcessFile fonksiyonunu dosya adı ile çağır
err := ProcessFile(filename)
// TODO: Hata zincirini inceleyerek sonucu işle
//
// ErrPermissionDenied'ın zincirde olup olmadığını kontrol etmek için errors.Is() kullan:
// - Eğer bulunursa: tam hatayı yazdır, ardından "Access denied - check file permissions" yazdır
//
// Zincirde bir *FileError olup olmadığını kontrol etmek için errors.As() kullan:
// - Eğer bulunursa: tam hatayı yazdır, ardından "File issue: [Filename] during [Operation]" yazdır
//
// Eğer hata yoksa: "File '[filename]' processed successfully" yazdır
_ = errors.Is // ipucu: errors.Is() kullan
_ = errors.As // ipucu: errors.As() kullan
_ = err
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1Go OOP Temelleri
Harici DosyalarGo Çalışma Alanı ve ModüllerPaketler ve İçe AktarmalarDışa Aktarılan ve Aktarılmayan İsimlerGo'da OOP'ye GirişSınıf Olarak Struct'larStruct'larda Metot TanımlamaPointer ve Değer AlıcılarStruct BaşlatmaYapıcı FonksiyonlarÖzet - Basit Hesap Makinesi4Arayüzler
Arayüzlere GirişÖrtük UygulamaSözleşme Olarak ArayüzBoş Arayüz (any)Tür OnaylamaTür SeçimiArayüz BileşimiStringer ve Error ArayüzleriÖzet - Şekil Hesaplayıcı7Kapsülleme
Dışa Aktarılan ve Aktarılmayan AlanlarPaket Seviyesinde KapsüllemeGetter ve Setter MetotlarıGo'da Bilgi GizlemeÖzet - Öğrenci Kayıtları10Generics (Go 1.18+)
Generics'e GirişTür ParametreleriTür KısıtlamalarıGeneric Struct'larGeneric Metotlar İçin Geçici ÇözümÖzet - Generic Koleksiyon13Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıAbstract Factory KalıbıObserver KalıbıStrategy Kalıbı2Türler ve Struct'lar: Derinlemesine İnceleme
Temel ve Bileşik TürlerÖzel Tür TanımlamalarıStruct EtiketleriAnonim Struct'larİç İçe Geçmiş Struct'larSıfır Değerler ve VarsayılanlarÖzet - Rehber5Kalıtım Yerine Kompozisyon
Go'da Neden Kalıtım YokStruct Gömme TemelleriMetot YükseltmeBirden Fazla Struct GömmeGömme vs AgregasyonGömülü Metotları GölgelemeÖzet - Çalışan Hiyerarşisi8Hata Yönetimi ve OOP
error ArayüzüÖzel Hata TürleriHata Sarmalama (fmt.Errorf)Sentinel Hatalarerrors.Is() ve errors.As()Panic, Defer ve RecoverÖzet - Dosya Ayrıştırıcı3İşaretçiler ve Bellek
Go'da İşaretçi TemelleriStruct İşaretçileriDeğer ile Geçme ve Referans ile Geçmenew() FonksiyonuGo'da Garbage CollectionÖzet - Linked List Oluşturucu6Go'da Polimorfizm
Interface'ler ile PolimorfizmGo'da Duck TypingInterface Karşılama KurallarıPolimorfik KoleksiyonlarDependency InjectionÖzet - Payment Processor9Eşzamanlılık ve OOP
Goroutine TemelleriKanallar ve İletişimTamponlu ve Tamponsuz KanallarSelect İfadesisync.Mutex ve sync.RWMutexsync.WaitGroupThread-Safe Struct TasarımıÖzet - Worker Pool