Ertelenen fonksiyonlar yalnızca defer deyimini içeren ana fonksiyonun çalışması tamamlandığında devreye girer. Buna normal çıkış, panik ve anormal çıkış da dahildir, sonuçta ertelenmiş fonksiyonlar her zaman işlem sonunda devreye girer. Ertelenen fonksiyonların en yaygın kullanım durumları, ana kontrol akışından hemen sonra açma/kapama, bağlantı/bağlantı kesme, kilitleme/kilit açma vb. işlemlerdir. Aşağıdaki örneklere bakabilirsiniz.


Örnekler


func main() {
fmt.Println("main: begin")
fmt.Println("main: 1")

defer child()

fmt.Println("main: 2")
fmt.Println("main: end")
}

func child() {
fmt.Println("child: begin")
fmt.Println("child: 1")
fmt.Println("child: end")
}

// main: begin
// main: 1
// main: 2
// main: end
// child: begin
// child: 1
// child: end

Aşağıda gösterildiği gibi, kaç kez çağrıldıklarına bakılmaksızın, ertelenen tüm işlevler sondan başa doğru olmak üzere çalışırlar.


func main() {
defer child(0)
fmt.Println("main: begin")

defer child(1)
fmt.Println("main: middle")
defer child(2)

fmt.Println("main: end")
defer child(3)
}

func child(i int) {
fmt.Printf("child: %d\n", i)
}

// main: begin
// main: middle
// main: end
// child: 3
// child: 2
// child: 1
// child: 0

Hatırlanması gereken önemli bir nokta ise, bir döngü içinde defer işlemi gerekirse, ilgili işlemleri ve defer deyiminin kendisi de dahil olmak üzere, ek bir fonksiyona taşımanız gerekir. Bunu yapmazsanız, kaynak "sızıntısına" neden olursunuz. Aşağıdaki farklara bakın.


// This is wrong!

func main() {
fmt.Println("main: begin")

for i := 1; i < 4; i++ {
defer child(i) // Resource leak.
}

fmt.Println("main: end")
}

func child(i int) {
fmt.Printf("child: %d\n", i)
}

// main: begin
// total: 8
// main: end
// child: 3
// child: 2
// child: 1

Yukarıdaki örnekte, ertelenen işlemlerin döngünün tamamının bitmesini beklemesi gerekecektir. Bu nedenle kaynak "sızıntısına" neden olur. Ancak, aşağıdaki örnekte böyle bir sorun yoktur, çünkü ertelenmiş işlemler her yinelemeden hemen sonra çalışırlar. Çıktılara dikkat edin.


// This correct!

func main() {
total := 1

fmt.Println("main: begin")

for i := 1; i < 4; i++ {
total = total * 2
middleman(i)
}

fmt.Printf("total: %d\n", total)
fmt.Println("main: end")
}

func middleman(i int) {
defer child(i)
}

func child(i int) {
fmt.Printf("child: %d\n", i)
}

// main: begin
// child: 1
// child: 2
// child: 3
// total: 8
// main: end