Menu
Coddy logo textTech

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(), hata zincirindeki herhangi bir hatanın belirli bir sentinel hatayla 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ı kontrol ederken errors.Is(), özel bir hata türündeki alanlara erişmeniz gerektiğinde ise errors.As() kullanın. Her iki işlev de hata zincirinin tamamını dolaşır; bu da onları sarmalanmış hataları düzgün bir şekilde ele almak için vazgeçilmez kılar.

challenge icon

Görev

Kolay

errors.Is() ve errors.As() kullanarak sarmalanmış hata zincirlerini nasıl doğru şekilde inceleyeceğimizi gösteren bir dosya işleme sistemi oluşturalım. Farklı katmanlardan geçerken sarmalanan hatalar oluşturacak, ardından bu işlevleri kullanarak bunları tanımlayıp içlerinden bilgi çıkaracaksın.

Kodunu iki dosyaya ayıracaksın:

  • errors.go: Dosya sistemin için hata altyapısını tanımla.

    Bir sentinel hata oluştur:

    • ErrPermissionDenied, mesajı "permission denied" olacak

    Özel bir hata türü oluştur:

    • FileError (string) ve Filename (string) alanlarına sahip Operation struct'ı
    • Error() metodu şu değeri döndürmeli: [Operation] failed on file: [Filename]

    Dosya işlemlerini simüle eden ve hataları sarmalayan iki işlev uygula:

    • ReadFile(filename string) error - filename "secret.txt" ise ErrPermissionDenied döndür. filename "missing.txt" ise Operation değeri *FileError ve verilen Filename ile bir "read" döndür. Aksi takdirde nil döndür.
    • ProcessFile(filename string) error - ReadFile işlevini çağırır. Bir hata döndürülürse fmt.Errorf biçimiyle "processing failed: %w" kullanarak hatayı sarmala. Aksi takdirde nil döndür.
  • main.go: Girdiden bir dosya adı oku ve ProcessFile işlevini çağır. Sarmalanmış hata zincirini incelemek ve içinde bulduğun bilgilere göre uygun mesajları yazdırmak için errors.Is() ve errors.As() kullan.

Aşağıdaki girdi sağlanacaktır:

  • 1. satır: İşlenecek dosya adı

Sonucu hata zincirini inceleyerek işle:

  • errors.Is() zincirde ErrPermissionDenied bulursa: tam hata mesajını yazdır, ardından yeni bir satırda Access denied - check file permissions yazdır
  • errors.As() zincirde bir *FileError bulursa: tam hata mesajını yazdır, ardından yeni bir satırda File issue: [Filename] during [Operation] yazdır
  • Hiç hata oluşmazsa: File '[filename]' processed successfully yazdır

Örneğin, secret.txt verildiğinde çıktın şöyle olmalıdır:

processing failed: permission denied
Access denied - check file permissions

Ve missing.txt verildiğinde çıktın şöyle olmalıdır:

processing failed: read failed on file: missing.txt
File issue: missing.txt during read

Ve data.txt verildiğinde çıktın şöyle olmalıdır:

File 'data.txt' processed successfully

Hatalar ProcessFile tarafından sarmalansa bile özgün sentinel hatasını errors.Is() ile hâlâ tespit edebileceğine ve özel hata türünü errors.As() ile çıkarabileceğine dikkat et. Bu işlevler, aradığın şeyi bulmak için hata zincirinin tamamını tarar.

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
}
quiz iconKendini test et

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

Kendi başına pratik yap: Online Go derleyicisi