ProgramlamaBackend geliştirici

Go'daki deferred işlev parametrelerinin çalışma özelliklerini açıklayın: defer için parametreler ne zaman ve nasıl hesaplanır ve bu, defer'in tetiklendiği anda işlev çağrısından nasıl farklıdır?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap.

Defer, mevcut işlev tamamlandıktan sonra, hatta panic meydana gelse bile bir işlevin çalıştırılmasını sağlayan benzersiz bir Go mekanizmasıdır. Tarihsel olarak, bu, on-exit yapılarının benzeri bir yapı ancak Go'da deferred çağrılarının bir yığını olarak uygulanmıştır. Önemli bir ayrıntı — deferred işlevin parametreleri defer'in beyan edilmesi anında hesaplanır, gerçek çağrısı sırasında değil!

Sorun — belirgin olmayan davranış: parametrelerin defer tetiklendiğinde geçirileceğini beklemek yaygındır, ancak öyle değildir. Bu genellikle değişkenlerle veya dış değişkenlerle çalışırken hatalara yol açar.

Çözüm — parametrelerin hemen hesaplandığını ve deferred çağrısının etkisinin sonradan meydana geleceğini her zaman göz önünde bulundurmak.

Kod örneği:

func f() { x := 5 defer fmt.Println(x) x = 10 } // Çıktı: 5, değil 10

Anahtar özellikler:

  • Deferred işlevleri için parametre değerleri defer'in beyan edildiği anda hesaplanır.
  • Deferred işlev her zaman çalışır, hatta panic durumunda (eğer panic daha önce yakalanmamışsa).
  • Eğer defer'de anonim bir işlev tanımlarsanız — o anki değişken değerlerine erişebilirsiniz.

Kandırmaca Sorular.

Aşağıdaki kod neyi yazdırır? Neden?

func main() { i := 0 defer fmt.Println(i) i = 1 }

Cevap: 0 yazdırır. fmt.Println işlevinin argümanı defer beyan edildiği anda saklanır.

Defer beyanından sonra değişkenin değiştirilmesi, değerin işleve aktarımını etkiler mi?

Hayır, etkilemez — hesaplama defer beyan edildiği anda gerçekleşir:

defer fmt.Println(x) // x'in değeri şu anda saklanır, sonra değil

Son durumda değişkeni nihai olarak yazdıracak bir defer yapabilir miyiz?

Evet, anonim bir işlev (closure) kullanarak:

defer func() { fmt.Println(x) }() // deferred çağrısı sırasında x'in güncel değerini alır

Tipik Hatalar ve Anti-Desenler

  • Parametrenin deferred çağrısının anında güncel olacağını beklemek.
  • Değişkenlerle birlikte parametrelerle defer kullanmak.
  • Açık bağımlılık tanımlarına sahip karmaşık defer yığınları.

Gerçek Hayattan Bir Örnek

Olumsuz Durum

Kod şu şekilde çağrılır:

var f *os.File // ... defer f.Close()

Ama f daha sonra atanır, bu nedenle nil işaretçisini çağırmaktan panic çıkacaktır!

Artılar:

  • Değişken zaten başlatıldıysa kısa yazım.

Eksiler:

  • Eğer f == nil ise — panic.

Olumlu Durum

Kontrol ile bir anonim deferred işlev aracılığıyla temizleme eylemini sarmak:

defer func() { if f != nil { f.Close() } }()

Artılar:

  • Güvenlik ve panik olmaması.

Eksiler:

  • Daha uzun ve "gürültülü" bir yazım.