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() 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.

challenge icon

Görev

Kolay

errors.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 sahip ErrPermissionDenied

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

    • Filename (string) ve Operation (string) alanlarına sahip FileError yapı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, ErrPermissionDenied döndürün. Eğer filename "missing.txt" ise, Operation değeri "read" olan ve verilen Filename'i içeren bir *FileError döndürün. Aksi takdirde nil döndürün.
    • ProcessFile(filename string) error - ReadFile fonksiyonunu çağırır. Eğer bir hata dönerse, bunu fmt.Errorf kullanarak "processing failed: %w" formatıyla sarmalayın. Aksi takdirde nil döndürün.
  • main.go: Girdiden bir dosya adı okuyun ve ProcessFile fonksiyonunu çağırın. Sarmalanmış hata zincirini incelemek için errors.Is() ve errors.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() zincirde ErrPermissionDenied bulursa: tam hata mesajını yazdırın, ardından yeni bir satırda Access denied - check file permissions yazdırın
  • Eğer errors.As() zincirde bir *FileError bulursa: tam hata mesajını yazdırın, ardından yeni bir satırda File issue: [Filename] during [Operation] yazdırın
  • Eğer hata oluşmazsa: File '[filename]' processed successfully yazdırın

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

processing failed: permission denied
Access denied - check file permissions

Ve missing.txt verildiğinde çıktınız şö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ız şöyle olmalıdır:

File 'data.txt' processed successfully

Hatalar 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
}
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