天天看點

go那些事兒|defer必掌握知識目錄defer執行時機defer執行順序defer與return誰先誰後函數包含多個Panic,defer中recover處理那個Panic函數傳回值遇到deferdefer遇到Panic練習:defer面試題閑聊歡迎加入我的公衆号【邁莫coding】 一起pk大廠

該文章始發于公衆号【邁莫coding】

連結:go那些事兒|defer必掌握知識

目錄

  • defer執行時機
  • defer執行順序
  • defer與return誰先誰後
  • 函數包含多個Panic,defer中recover處理那個Panic
  • 函數傳回值遇到defer
  • defer遇到Panic
    • defer遇到Panic,但是并不捕獲異常的情況
    • defer遇到Panic,并捕獲異常
  • 練習:defer面試題
  • 閑聊
  • 歡迎加入我的公衆号【邁莫coding】 一起pk大廠

defer執行時機

  • return 語句執行完之後,如果有 defer 語句,再執行 defer 語句
  • 發生 Panic ,也會觸發 defer 執行

defer執行順序

多個defer出現時,會以"先進後出,後進先出"的規則來執行,類似于資料結構中棧的執行順序.

示例:

package main 

import "fmt"

func main() {
  defer func(){
    fmt.Println("A")
  }()
  defer func(){
    fmt.Println("B")
  }
  defer func(){
    fmt.Println("C")
  }
}
           

結果:

C
B
A
           

defer與return誰先誰後

示例代碼

package main 

import "fmt"

func deferFunc() {
  fmt.Println("defer func")
}

func returnFunc() int {
  fmt.Println("return func")
  return 1
}

func returnAndDefer() int {
  defer deferFunc()
  return returnFunc()
}

func main() {
  returnAndDefer()
}
           

結果

return func
defer func
           

結論

一個函數中即有return語句,也有defer語句,先執行return語句,後執行defer語句
           

函數包含多個Panic,defer中recover處理那個Panic

示例

package main

import "fmt"

func main() {
  defer func() {
    if err := recover(); err != nil {
      fmt.Println(err)
    }else {
      fmt.Println("fail")
    }
  }()
  defer func() {
    panic("defer panic")
  }()
  panic("main panic")
}
           

結果

結論

函數傳回值遇到defer

示例

package main

import "fmt"

func deferFunc() (t int) { // t初始化為0,并且作用域為該函數全域
  defer func() {
    t = t * 10
  }()
  return 1
}

func main() {
  fmt.Println(deferFunc())
}
           

結果

結論

當調用deferFunc()函數時,本應該傳回值1,但函數中還有defer語句,
是以在return語句之後,又被defer的匿名函數func函數執行,
是以t=t*10被執行。是以傳回值為10.
           

defer遇到Panic

defer遇到Panic,但是并不捕獲異常的情況

示例

package main

import "fmt"

func defer_panic() {
  defer func() {
    fmt.Println("defer: panic() 執行1")
  }()
  defer func() {
     fmt.Println("defer: panic() 執行2")
  }
  panic("發生異常")
  fmt.Println("該條語句無法執行")
}
func main() {
  defer_panic()
  fmt.Println("main函數執行完成")
}
           

結果

defer: panic() 執行2
defer: panic() 執行1
panic: 發生異常
// 異常資訊...
           

defer遇到Panic,但捕獲異常的情況

示例

package main

import "fmt"

func defer_panic() {
  defer func() {
    fmt.Println("defer: panic() 執行1")
    if err := recover(); err != nil {
      fmt.Println(err)
    }
  }()
  defer func() {
     fmt.Println("defer: panic() 執行2")
  }
  panic("發生異常")
  fmt.Println("該條語句無法執行")
}
func main() {
  defer_panic()
  fmt.Println("main函數執行完成")
}
           

結果

defer: panic() 執行2
defer: panic() 執行1
發生異常
main函數執行完成
           

練習:defer面試題

1. 下面代碼輸出什麼?

package main

import "fmt"

func main() {
   var name = "zhangsan"
   fmt.Println(name)
   defer fmt.Println(name)
   name = "lisa"
   fmt.Println(name)
   defer fmt.Println(name)
}
           
考點
defer和函數組合調⽤方式 
           
結果
zhangsan lisa lisa zhangsan 
           

2. 程式運作結果

示例
package main
import (
   "fmt"
)
func main() {
   defer_call()
}
func defer_call() {
   defer func() { fmt.Println("邁") }()
   defer func() { fmt.Println("莫") }()
   defer func() { fmt.Println("coding") }()
}
           
考點
defer和函數組合調⽤方式 
           
結果
coding
莫
邁
           

3. 下面代碼輸出什麼?

示例
package main
import "fmt"
func DeferFunc1(i int) (t int) {
    t = i
    defer func() {
        t += 3
    }()
    return t
}

func main() {
    fmt.Println(DeferFunc1(1))
}
           
考點
defer和函數組合調⽤方式 
           
結果
執行過程
1. 将傳回值t指派為行參i,t = 1
2. 執行return語句,将t 指派給t
3. 執行defer語句,t + 3 = 4
4. 傳回值4
           

4. 下面代碼輸出什麼?

示例
package main
import "fmt"
func DeferFunc2(i int) int {
    t := i
    defer func() {
        t += 3
    }()
    return t
}

func main() {
    fmt.Println(DeferFunc2(1))
}
           
考點
defer和函數組合調⽤方式 
           
結果
執行過程
1. 建立變量t并将其指派為i的值,t = 1
2. 執行return語句,注意這裡是将t指派給傳回值,此時傳回值為1(這個傳回值并不是t)
3.執行defer語句,t = t + 3 = 4
4. 函數傳回值1
           

5. 下面代碼輸出什麼?

示例
package main
import "fmt"

func DeferFunc3(i int) (t int) {
    defer func() {
        t += i
    }()
    return 2
}

func main() {
    fmt.Println(DeferFunc3(1))
}
           
考點
defer和函數組合調⽤方式 
           
結果
執行過程
1. 首先将t指派為2
2. 執行defer語句,t = t + 1 = 3
3. 函數傳回值3
           

6. 下面代碼輸出什麼?

示例
package main
import "fmt"

func DeferFunc4() (t int) {
    defer func(i int) {
        fmt.Println(i)
        fmt.Println(t)
    }(t)
    t = 1
    return 2
}
func main() {
    DeferFunc4()
}
           
考點
defer和函數組合調⽤方式 
           
結果
0
2
           
執行過程
1. 初始化傳回值t為零值 0
2. 首先執行defer的第一步,指派defer中的func入參t為0
3. 執行defer的第二步,将defer壓棧
4. 将t指派為1
5. 執行return語句,将傳回值t指派為2
6. 執行defer的第三步,出棧并執行
7. 因為在入棧時defer執行的func的入參已經指派了,此時它作為的是一個形式參數,是以列印為0;
8. 相對應的因為最後已經将t的值修改為2,是以再列印一個2
           

閑聊

  • 讀完文章,自己是不是和defer的cp率又提高了
  • 我是邁莫,歡迎大家和我交流
原創不易,覺得文章寫得不錯的小夥伴,點個贊👍 鼓勵一下吧~

歡迎加入我的公衆号【邁莫coding】 一起pk大廠

- 邁莫coding歡迎客官的到來

go那些事兒|defer必掌握知識目錄defer執行時機defer執行順序defer與return誰先誰後函數包含多個Panic,defer中recover處理那個Panic函數傳回值遇到deferdefer遇到Panic練習:defer面試題閑聊歡迎加入我的公衆号【邁莫coding】 一起pk大廠

繼續閱讀