Menu
Coddy logo textTech

Panic, Defer ve Recover

Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 57 / 107.

Go, hataları döndürmeyi vurgulasa da, bazı durumlar gerçekten kurtarılamazdır. Bu durumlar için Go, olağanüstü durumları yönetmek için bir mekanizma olan panic, defer ve recover sağlar.

panic normal yürütmeyi anında durdurur. Geçersiz kullanıcı girişi gibi beklenen hatalar için değil, sınır dışı bir dizine erişmek gibi programlama hataları için ayrılmıştır:

func MustGetConfig(key string) string {
    value, exists := config[key]
    if !exists {
        panic("missing required config: " + key)
    }
    return value
}

defer, çevreleyen fonksiyon döndüğünde —ister normal bir şekilde ister bir panik (panic) nedeniyle olsun— bir fonksiyonun çalışmasını planlar. Ertelenmiş çağrılar ters sırada (son giren, ilk çıkar) yürütülür:

func ProcessFile() {
    fmt.Println("Opening file")
    defer fmt.Println("Closing file")
    fmt.Println("Processing...")
    // Çıktı: Opening file, Processing..., Closing file
}

recover bir paniği yakalar ve normal yürütmeye geri döner. Sadece ertelenmiş bir fonksiyonun içinde çalışır:

func SafeOperation() (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("recovered from panic: %v", r)
        }
    }()
    
    riskyOperation()
    return nil
}

Bu desen, bir panik durumunu (panic) normal bir hataya dönüştürerek programınızın devam etmesine olanak tanır. Bunu idareli kullanın; beklenen hata durumları için hata döndürmeyi tercih edin ve panic/recover mekanizmasını bozulmuş durum veya kurtarılamaz koşullar gibi gerçekten istisnai durumlar için saklayın.

challenge icon

Görev

Kolay

Olağanüstü durumları zarif bir şekilde yönetmek için panic, defer ve recover mekanizmalarının nasıl kullanılacağını gösteren güvenli bir bölme hesap makinesi oluşturalım. Hesap makineniz riskli işlemleri deneyecek ve panikleri normal şekilde işlenebilen standart hatalara dönüştürecektir.

Kodunuzu iki dosya halinde düzenleyeceksiniz:

  • calculator.go: Panik kurtarma özelliğine sahip bölme mantığını oluşturun.

    İki tam sayı alan ve bölen sıfırsa "division by zero" mesajıyla panikleyen bir Divide fonksiyonu uygulayın. Aksi takdirde, bölme işleminin tam sayı sonucunu döndürür.

    İki tam sayı alan ve hem bir tam sayı sonucu hem de bir hata döndüren bir SafeDivide fonksiyonu uygulayın. Bu fonksiyon şunları yapmalıdır:

    • Herhangi bir panikten kurtulmak için anonim bir fonksiyonla defer kullanın
    • Eğer bir panik kurtarılırsa, bunu "calculation error: [panic message]" formatında bir hataya dönüştürün
    • Dahili olarak Divide fonksiyonunu çağırın
    • Başarılıysa sonucu ve nil döndürün, bir panik kurtarıldıysa sıfır ve hatayı döndürün
  • main.go: Girdiden iki tam sayı okuyun ve hesaplamayı güvenli bir şekilde gerçekleştirmek için SafeDivide kullanın. Ayrıca temizlik mesajlarını doğru sırayla yazdırarak defer kullanımını gösterin.

    Ana fonksiyonunuz şunları yapmalıdır:

    • Başlangıçta Starting calculation yazdırın
    • Cleanup complete yazdırmayı planlamak için defer kullanın
    • Releasing resources yazdırmayı planlamak için başka bir defer kullanın
    • Girdi değerleriyle SafeDivide fonksiyonunu çağırın
    • Sonuca bağlı olarak Result: [value] veya Error: [error message] yazdırın

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

  • Satır 1: İlk tam sayı (bölünen)
  • Satır 2: İkinci tam sayı (bölen)

Ertelenmiş (deferred) çağrıların ters sırada (son giren ilk çıkar - LIFO) yürütüldüğünü unutmayın, bu nedenle temizlik mesajlarınız ertelendikleri sıranın tersi yönünde görünmelidir.

Örneğin, 20 ve 4 verildiğinde çıktınız şöyle olmalıdır:

Starting calculation
Result: 5
Releasing resources
Cleanup complete

Ve 10 ile 0 verildiğinde çıktınız şöyle olmalıdır:

Starting calculation
Error: calculation error: division by zero
Releasing resources
Cleanup complete

Kopya kağıdı

Go, istisnai durumları yönetmek için panic, defer ve recover sağlar.

panic normal yürütmeyi anında durdurur ve kurtarılamaz programlama hataları için ayrılmıştır:

func MustGetConfig(key string) string {
    value, exists := config[key]
    if !exists {
        panic("missing required config: " + key)
    }
    return value
}

defer, çevreleyen fonksiyon döndüğünde çalışacak bir fonksiyon planlar. Ertelenen çağrılar ters sırada (son giren ilk çıkar) yürütülür:

func ProcessFile() {
    fmt.Println("Opening file")
    defer fmt.Println("Closing file")
    fmt.Println("Processing...")
    // Çıktı: Opening file, Processing..., Closing file
}

recover bir paniği yakalar ve normal yürütmeye geri döner. Sadece ertelenmiş bir fonksiyonun içinde çalışır:

func SafeOperation() (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("recovered from panic: %v", r)
        }
    }()
    
    riskyOperation()
    return nil
}

Bu desen, bir paniği normal bir hataya dönüştürür. Beklenen hatalar için hata döndürmeyi tercih edin ve panic/recover mekanizmasını gerçekten istisnai durumlar için saklayın.

Kendin dene

package main

import (
	"fmt"
)

func main() {
	// Girdiyi oku
	var dividend, divisor int
	fmt.Scanln(&dividend)
	fmt.Scanln(&divisor)

	// Başlangıç mesajını yazdır
	fmt.Println("Starting calculation")

	// TODO: "Cleanup complete" mesajını planlamak için defer kullanın

	// TODO: "Releasing resources" mesajını planlamak için defer kullanın
	// Unutmayın: ertelenmiş çağrılar LIFO düzeninde (son giren ilk çıkar) yürütülür

	// TODO: SafeDivide fonksiyonunu girdi değerleriyle çağırın

	// TODO: Ya "Result: [value]" ya da "Error: [error message]" yazdırın
	// bir hata döndürülüp döndürülmediğine bağlı olarak
}
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