溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

golang中的defer函數(shù)

發(fā)布時間:2020-06-21 21:07:04 來源:億速云 閱讀:171 作者:鴿子 欄目:編程語言

Go語言的defer算是一個語言的新特性,至少對比當(dāng)今主流編程語言如此。

defer語句調(diào)用一個函數(shù),這個函數(shù)執(zhí)行會推遲,直到外圍的函數(shù)返回,或者外圍函數(shù)運行到最后,或者相應(yīng)的goroutine panic

每當(dāng)defer執(zhí)行的時候,它后面的函數(shù)值(在go中函數(shù)是一個引用類型,是一等公民,可以賦值給變量)和函數(shù)參數(shù)會被求值,但是函數(shù)不會立即調(diào)用,直到(↑)上述三種情況發(fā)生。 這就是defer的全部內(nèi)容,沒了,剩下就是defer的best practice

函數(shù)不會立即調(diào)用

先從最簡單的開始:

func readFile(fileName string){
    f,err := os.Open(fileName)
    if err!=nil {
        return
    }
    defer f.Close()
    var content [1024]byte
    f.Read(content[:])
    fmt.Printf("%s",content)
}
func main() {
    readFile("test.data")
}

程序輸出test.data前1024字節(jié)的內(nèi)容。值得一提的是,類似這種open/close配對操作是defer的慣用法。 這個例子詮釋了上面那句話的后半段

"但是函數(shù)不會被調(diào)用"

因為如果defer后面的f.Close()沒有延遲執(zhí)行,那么文件描述符都關(guān)閉了,就不會讀取到任何內(nèi)容。

函數(shù)值和函數(shù)參數(shù)被求值,但函數(shù)不會立即調(diào)用

下面這個例子即將詮釋上半段,它來自<>,稍作修改:

func trace(funcName string) func(){
    start := time.Now()
    fmt.Printf("function %s enter\n",funcName)
    return func(){
        log.Printf("function %s exit (elapsed %s)",funcName,time.Since(start))
    }
}
 
func foo(){
    defer trace("foo()")()
    time.Sleep(5*time.Second)
}
func main(){
    foo()
    foo()
}
/*
OUTPUT:
function foo() enter
function foo() exit (elapsed 5.0095471s)
function foo() enter
function foo() exit (elapsed 5.0005382s)
*/

為什么foo會輸出enter然后等待五秒左右再輸出exit? 因為正如我們說的,

defer后面的函數(shù)值和參數(shù)會被求值但是實際函數(shù)調(diào)用卻要等到最后

這里函數(shù)值就是trace()返回的匿名函數(shù),函數(shù)參數(shù)當(dāng)然就是字符串字面值"foo()", 對trace("foo()")的求值會輸出function foo() enter, 實際函數(shù)調(diào)用trace("foo()")()即輸出function foo() exit(elapsed x.x)會推遲到return執(zhí)行(如果return會更新返回值變量,則會在更新后才執(zhí)行defer的函數(shù))。

雜項

多說一點,如果存在多個defer語句,最后的defer的函數(shù)的執(zhí)行順序與defer出現(xiàn)的順序相反,如:

func main() {
    func1 := func(){
        fmt.Println("func1() execution deferred")
    }
    func2 := func(){
        fmt.Println("func2() execution deferred")
    }
    defer func1()
    defer func2()
    fmt.Println("strat\nworking...")
}
/*
OUTPUT:
strat
working...
func2() execution deferred
func1() execution deferred
*/

以上就是go defer(go延遲函數(shù))介紹的詳細(xì)內(nèi)容,更多請關(guān)注億速云其它相關(guān)文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI