天天看點

go09---defer

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")
}