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.
Görev
KolayOlağ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 birDividefonksiyonu 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
SafeDividefonksiyonu uygulayın. Bu fonksiyon şunları yapmalıdır:- Herhangi bir panikten kurtulmak için anonim bir fonksiyonla
deferkullanın - Eğer bir panik kurtarılırsa, bunu
"calculation error: [panic message]"formatında bir hataya dönüştürün - Dahili olarak
Dividefonksiyonunu çağırın - Başarılıysa sonucu ve
nildöndürün, bir panik kurtarıldıysa sıfır ve hatayı döndürün
- Herhangi bir panikten kurtulmak için anonim bir fonksiyonla
main.go: Girdiden iki tam sayı okuyun ve hesaplamayı güvenli bir şekilde gerçekleştirmek içinSafeDividekullanın. Ayrıca temizlik mesajlarını doğru sırayla yazdırarakdeferkullanımını gösterin.Ana fonksiyonunuz şunları yapmalıdır:
- Başlangıçta
Starting calculationyazdırın Cleanup completeyazdırmayı planlamak içindeferkullanınReleasing resourcesyazdırmayı planlamak için başka birdeferkullanın- Girdi değerleriyle
SafeDividefonksiyonunu çağırın - Sonuca bağlı olarak
Result: [value]veyaError: [error message]yazdırın
- Başlangıçta
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 completeVe 10 ile 0 verildiğinde çıktınız şöyle olmalıdır:
Starting calculation
Error: calculation error: division by zero
Releasing resources
Cleanup completeKopya 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(÷nd)
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
}
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