GO 中的 defer 有哪些注意事項?上

阿兵雲原生發表於2023-03-01

xdm , 不知道你們是否有使用過 defer ,這種語法在是 go 特有的,用起來真是爽的不要不要的

很多時候,我們在使用一些新東西,出現一些莫名其妙的現象或者是結果的時候,我們總會認為,這個東西不友好, 這個東西好坑,好奇怪

其實我們是要弄明白其中的注意點,原理,當出現所謂的奇怪現象的時候,處理起來就會得心應手得多

xdm,這裡準備瞭如下注意事項,請查收

案例 1

這裡先統一說明一下 defer 是幹什麼的?

是 GO 中的一個關鍵字

這個關鍵字,我們一般用在釋放資源,在 return 前會呼叫他

如果程式中有多個 defer ,defer 的呼叫順序是按照類似的方式,後進先出 LIFO的 , 具體的 defer 實現原理可以檢視我的歷史文章 GO 中 defer的實現原理

先來看一個 demo,猜一猜他的輸出是什麼?

寫一個 defer 和 defer 在一起的 輸入輸出順序 demo

  • 簡單寫 4 個函式,分別應用到 defer 上
func test1() {
    fmt.Println("test 1")
}
func test2() {
    fmt.Println("test 2")
}
func test3() {
    fmt.Println("test 3")
}
func test4() {
    fmt.Println("test 4")
}
func main() {
    defer test1()
    defer test2()
    defer test3()
    defer test4()
}

執行上述程式碼,我們期望的結果是什麼呢?

test 1
test 2
test 3
test 4

還是

test 4
test 3
test 2
test 1

小夥伴們感興趣的可以執行一下,結果是 第二種,defer 我們可以理解為是一個入棧操作,先進後出

入棧 : test1(),test2(),test3(),test4()

出棧 : test4(),test3(),test2(),test1()

案例 2

上面我們知道 defer 和 defer 的順序是按照棧的順序來,那麼我們下面來看看 defer 和 return 的順序又是什麼樣子的 ?

  • 簡單寫 一個用於 return 的函式和 用於 defer 的函式
func testDefer() {
    fmt.Println("testDefer")
}
func testReturn() int {
    fmt.Println("testReturn")
    return 1
}
func myTest() int {
    defer testDefer()
    return testReturn()
}
func main() {
    myTest()
}

再來猜測一下上述編碼會是如何執行的呢

是這樣的嗎?

testDefer
testReturn

還是這樣的 ?

testReturn
testDefer

結果仍然是第二種,透過上述編碼我們可以看出來 defer 後面的語句 是晚執行的, return 後面的語句是先執行的

那麼如果是 多個 defer 和 return 放在一起呢?

xdm ,我們們舉一反三了,那肯定還是 return 先執行,defer 按照棧的順序執行

案例 3

這個案例我們們加上簡單的計算,看看效果如何

  • 簡單些一下帶有計算的 defer
func testDefer(num int)(res int){

    defer func(){
        res = num + 3
    }()

    return num
}

func main(){

    res := testDefer(5)
    fmt.Println(res)
}

上述編碼執行後會是什麼效果呢

是 5 嗎? 是 8 嗎?反正肯定不是 3 吧

思考一下,按照上面案例 1 的邏輯,結果是 8

老鐵,沒毛病, num 透過 testDefer 函式傳值,賦值 為 5 ,return num 的時候,返回值是 5,再執行 defer 語句, 5+3 就是 8

好了,今天就到這裡,感興趣的朋友也可以玩起來

歡迎點贊,關注,收藏

朋友們,你的支援和鼓勵,是我堅持分享,提高質量的動力

好了,本次就到這裡

技術是開放的,我們的心態,更應是開放的。擁抱變化,向陽而生,努力向前行。

我是阿兵雲原生,歡迎點贊關注收藏,下次見~

相關文章