package main
/*
defer
類似其它語言中的析構函數,在函數體執行結束後
按照調用順序的相反順序逐個執行,先進後出,
即使函數發生嚴重錯誤也會執行,資源清理檔案關閉,
支援匿名函數的調用
常用于資源清理、檔案關閉、解鎖以及記錄時間等操作
通過與匿名函數配合可在return之後修改函數計算結果
如果函數體内某個變量作為defer時匿名函數的參數,則在定義defer
時即已經獲得了拷貝,如果不是參數則是引用某個變量的位址
Go 沒有異常機制,但有 panic/recover 模式來處理錯誤
Panic 可以在任何地方引發,但recover隻有在defer調用的函數中有效
*/
import (
"fmt"
)
func main1() {
fmt.Println("a")
defer fmt.Println("b")
defer fmt.Println("c") //acb,相反順序逐個執行,先進後出,
}
func main2() {
fmt.Println("a")
defer fmt.Println("b")
defer fmt.Println("c")
for i := 0; i < 3; i++ {
defer fmt.Println(i)
} // a 2 1 0 c b
}
func main3() {
for i := 0; i < 3; i++ {
defer func() {
fmt.Println(i)
}() // 3 3 3,for循環結束的時候i=3,而當main函數結束的時候開始執行defer,此時i一直是3(存在閉包)
}
}
//go語言沒有異常機制,也就是沒有try catch,defer就類似于finally,
//go語言的異常機制是panic/recover 模式來處理錯誤,Panic 可以在任何地方引發,但recover隻有在defer調用的函數中有效
//函數發生錯誤的時候,函數已經不執行了,隻能靠defer來執行一些恢複操作,是以recover隻能放在defer調用的函數中才是有意義的。
func main4() {
A()
B()
C() //AAAAAAA, panic:BBBBBBBB
}
func A() {
fmt.Println("AAAAAAA")
}
func B() {
panic("BBBBBBBB") //B已經panic了,C函數不執行,程式終止執行了,
}
func C() {
fmt.Println("VCCCCCC")
}
func main() {
A1()
B1()
C1()
//AAAAAAA recover in B VCCCCCC
//通過defer将程式從panic狀态恢複回來,恢複到正常執行,
}
func A1() {
fmt.Println("AAAAAAA")
}
func B1() {
//恢複panic,要寫在panic之前,因為如果執行了panic了後面的代碼不再執行了,
//那麼defer就注冊不了recover函數了,(defer函數是在函數執行完之後執行的,相當于隻是注冊了裡面的一些函數)
defer func() {
if err := recover(); err != nil { //err為函數中出現的錯誤,err不為空,引發了panic,說明revcover有效,恢複panic,
fmt.Println("recover in B")
}
}()
panic("BBBBBBBB") //B已經panic了,C函數不執行,程式終止執行了,
}
func C1() {
fmt.Println("VCCCCCC")
}