Golang Defer

Defer

Go的控制流有一些常用的機制:if, for, switch, goto. 它也擁有可以在獨立的goroutine中運行代碼的go語句。接下來會介紹通常比較少用到的類型:defer, panic, recover.

defer語句將函數(shù)調(diào)用壓入一個列表。當(dāng)包圍defer的函數(shù)返回的時候,列表中緩存的調(diào)用開始執(zhí)行。Defer語句是用來簡化各種各樣的清除操作的。

例如,當(dāng)需要打開兩個文件,將其中一個文件的內(nèi)容拷貝到另外一個文件的時候:

func CopyFile(dstName, srcName string) (written int64, err error) {
    src, err := os.Open(srcName)
    if err != nil {
        return
    }
    
    dst, err := os.Create(dstName)
    if err != nil {
        return
    }
    
    written, err = io.Copy(dst, src)
    dst.Close()
    src.Close()
    return
}

上面的代碼可以工作,但是會有一個Bug。如果調(diào)用os.Create失敗,這個函數(shù)就會立即返回卻沒有關(guān)閉源文件。當(dāng)然,可以在出現(xiàn)error的地方加上src.Close方法,但是如果這個函數(shù)非常復(fù)雜,這個問題就會很難被注意到。當(dāng)引入defer語句,這個問題就會很容易被解決:

func CopyFile(dstName, srcName string) (written int64, err error) {
    src, err := os.Open(srcName)
    if err != nil {
        return
    }
    defer src.Close()
    
    dst, err := os.Create(dstName)
    if err != nil {
        return
    }
    defer dst.Close()
    
    return io.Copy(dst, src)
}

Defer 語句可以確保我們打開文件之后會關(guān)閉這些文件,不管函數(shù)中有多少個return語句。

Defer 語句的行為非常直接,可以預(yù)測。有三個簡單的規(guī)則:

  1. defer語句指定的函數(shù)中的變量是當(dāng)執(zhí)行到defer語句的時候就確定了的;
    在下面的例子中,表達(dá)式“i”的值當(dāng)Println被defer的時候就確定了的,所以下面的輸出是0,而不是1

    func a() {
        i := 0
        defer fmt.Println(i)
        i++
        return
    }
    
  2. 多個defer 語句執(zhí)行的順序是后進(jìn)先出的。
    下面的函數(shù)打印“3210”

    func b() {
        for i := 0; i < 4; i++ {
            defer fmt.Print(i)
        }
    }
    
  3. 被Defer的函數(shù)可以讀取并且修改外層函數(shù)的被命名的返回值
    在下面的例子中,當(dāng)外層函數(shù)返回的時候,defer函數(shù)執(zhí)行,并且將返回值加1,所以這個函數(shù)返回的是2.

    func c() (i int) {
        defer func() {i++} ()
        return 1
    }
    
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容