1. Golang'da defer
özelliğine giriş
Go dilinde, defer
ifadesi, içinde bulunduğu fonksiyonun çalışmasını tamamlayıp bitene kadar erteler. Diğer programlama dillerindeki finally
bloğuna benzetebilirsiniz, ancak defer
'ın kullanımı daha esnek ve benzersizdir.
defer
kullanmanın faydası, dosyaları kapatma, mutex'lari kilitleme veya sadece bir fonksiyonun çıkış zamanını kaydetme gibi temizleme görevlerini yapmak için kullanılabilmesidir. Bu, programı daha sağlam hale getirebilir ve istisna işleme konusundaki programlama işini azaltabilir. Go'nun tasarım felsefesinde, defer
kullanımı, hataları ele alırken, kaynak temizliği yaparken ve diğer sonraki işlemleri yaparken kodu kısa tutmaya ve okunabilir tutmaya yardımcı olduğu için önerilmektedir.
2. defer
'ın çalışma prensibi
2.1. Temel çalışma prensibi
defer
'ın temel çalışma prensibi, her ertelenmiş fonksiyonu çalıştırmak için bir yığın (son giren, ilk çıkar prensibi) kullanmaktır. Bir defer
ifadesi ortaya çıktığında, Go dili derhal ifadeyi takip eden fonksiyonu çalıştırmaz. Bunun yerine, onu ayırt edilmiş bir yığına iter. Şimdiye kadar sona ermesi planlanan dış fonksiyon, bu ertelenmiş fonksiyonları yığın sırasına göre sırayla çalıştırır, en son tanımlanan defer
ifadesindeki fonksiyon en önce çalıştırılır.
Ayrıca, defer
ifadesini takip eden fonksiyonlardaki parametrelerin, gerçek yürütülmede hesaplanıp sabitlendiğini, ertelendiği anda dikkate almak önemlidir.
func ornek() {
defer fmt.Println("dünya") // ertelendi
fmt.Println("merhaba")
}
func main() {
ornek()
}
Yukarıdaki kod şunu çıktılar:
merhaba
dünya
dünya
, örnek
fonksiyonu çıkışından önce yazdırılır, kod içinde merhaba
'dan önce görünmesine rağmen.
2.2. Birden fazla defer
ifadesinin çalıştırılma sırası
Bir fonksiyonda birden fazla defer
ifadesi olduğunda, bunlar son giren, ilk çıkar prensibine göre çalıştırılır. Bu, karmaşık temizleme mantığını anlamak için genellikle çok önemlidir. Aşağıdaki örnek, birden fazla defer
ifadesinin çalıştırılma sırasını göstermektedir:
func cokluDeferred() {
defer fmt.Println("İlk erteleme")
defer fmt.Println("İkinci erteleme")
defer fmt.Println("Üçüncü erteleme")
fmt.Println("Fonksiyon bloğu")
}
func main() {
cokluDeferred()
}
Bu kodun çıktısı şu olacaktır:
Fonksiyon bloğu
Üçüncü erteleme
İkinci erteleme
İlk erteleme
Çünkü defer
, son giren, ilk çıkar prensibini takip ettiği için, "İlk erteleme" en son ertelenen olsa da en son olarak çalıştırılır.
3. Farklı senaryolardaki defer
'ın uygulamaları
3.1. Kaynak serbest bırakma
Go dilinde, defer
ifadesi, dosya işlemleri ve veritabanı bağlantıları gibi kaynak serbest bırakma mantığını ele almak için yaygın olarak kullanılır. defer
, fonksiyonun herhangi bir nedenle çıkmasına bakılmaksızın, ilgili kaynakların doğru bir şekilde serbest bırakılmasını sağlar.
Dosya işlemi örneği:
func DosyaOku(dosyaAdi string) {
dosya, err := os.Open(dosyaAdi)
if err != nil {
log.Fatal(err)
}
// Dosyanın kapatılmasını sağlamak için defer kullanın
defer dosya.Close()
// Dosya okuma işlemleri yapılır...
}
Bu örnekte, os.Open
dosyayı başarıyla açtığında, ardışık defer dosya.Close()
ifadesi, fonksiyon sona erdiğinde dosya kaynağının doğru bir şekilde kapatılmasını ve dosya işaretçi kaynağının serbest bırakılmasını sağlar.
Veritabanı Bağlantısı Örneği:
func VeritabaniSorgusu(sorgu string) {
db, err := sql.Open("mysql", "kullanici:şifre@/veritabanıAdı")
if err != nil {
log.Fatal(err)
}
// Defer kullanarak veritabanı bağlantısının kapatılmasını sağlayın
defer db.Close()
// Veritabanı sorgu işlemleri yapılır...
}
Benzer şekilde, defer db.Close()
veritabanı bağlantısının, VeritabaniSorgusu
fonksiyonunu terk ettiğinde kapatılmasını, performansın normal dönüş ya da istisna fırlatılmasına bakılmaksızın sağlar.
3.2. Eş zamanlı programlamada Kilit İşlemleri
Eş zamanlı programlamada, mutex kilitlerin serbest bırakılmasını ele almak için defer
kullanma iyi bir uygulamadır. Bu, kritik bölüm kodunun yürütülmesinden sonra kilidin doğru bir şekilde serbest bırakılmasını sağlayarak kilitlenmeleri önler.
Mutex Kilit Örneği:
var mutex sync.Mutex
func updateSharedResource() {
mutex.Lock()
// Kilidin serbest bırakılmasını sağlamak için defer kullanın
defer mutex.Unlock()
// Paylaşılan kaynağa yapılan değişiklikler yapılır...
}
Paylaşılan kaynağın değiştirilip değiştirilmediğine bakılmaksızın veya araya bir panik girse bile, defer
diğer gorutinlerin kilidi almasına izin vermek için Unlock()
'un çağrılmasını sağlayacaktır.
İpucu: Mutex kilitlerinin detaylı açıklamaları sonraki bölümlerde ele alınacaktır. Bu noktada defer'ın uygulama senaryolarını anlamak yeterlidir.
defer
için 3 Ortak Sorun ve Dikkat Edilmesi Gerekenler
defer
kullanırken, kodun okunabilirliği ve bakımı büyük ölçüde artsa da, dikkate alınması gereken bazı sorunlar ve konular da mevcuttur.
3.1 Defer'a aktarılan fonksiyon parametreleri hemen değerlendirilir
func printValue(v int) {
fmt.Println("Değer:", v)
}
func main() {
value := 1
defer printValue(value)
// `value`'un değerini değiştirmek, defer'a zaten iletilmiş olan parametreyi etkilemeyecektir
value = 2
}
// Çıktı "Değer: 1" olacaktır
Defer ifadesinden sonra value
'nun değeri değişse bile, defer'da printValue'a iletilen parametre zaten değerlendirilmiş ve sabitlendiği için çıktı hala "Değer: 1" olacaktır.
3.2 Döngüler içinde defer kullanırken dikkatli olun
Döngü içinde defer kullanmak, kaynakların döngü bitmeden serbest bırakılmamasına ve bu durumun kaynak sızıntılarına veya tükenmeye yol açmasına neden olabilir.
3.3 Eş zamanlı programlamada "kullanımdan sonra serbest bırak"tan kaçının
Eş zamanlı programlarda, kaynakları serbest bırakmak için defer kullanırken, kaynağa erişmeye çalışacak olan tüm gorutinlerin kaynağa erişmeye çalışmamasını sağlamak için serbest bırakıldıktan sonra, yarış koşullarını önlemek önemlidir.
4. defer
ifadelerinin yürütme sırasına dikkat edin
defer
ifadeleri Son Giren İlk Çıkar (LIFO) prensibini takip eder, yani en son tanımlanan defer
önce yürütülür.
Çözümler ve En İyi Uygulamalar:
- Defer ifadelerindeki fonksiyon parametrelerinin ifadenin tanımlandığı zamanda değerlendirildiğini her zaman farkında olun.
- Döngü içinde defer kullanırken, anonim fonksiyonlar kullanmayı veya kaynak serbest bırakımını açıkça çağırmayı düşünün.
- Eş zamanlı bir ortamda, kaynakları serbest bırakmak için defer kullanmadan önce, tüm gorutinlerin işlemlerini tamamladığından emin olun.
- Birden fazla
defer
ifadesi içeren fonksiyonlar yazarken, yürütme sıralarını ve mantığı dikkatlice düşünün.
Bu en iyi uygulamaları takip etmek, defer
kullanımı sırasında karşılaşılan çoğu sorunu önlemenizi sağlar ve daha sağlam ve bakımı kolay Go kodu yazmanıza yol açar.