該文章始發于公衆号【邁莫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歡迎客官的到來
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiclRnblN2XjlGcjAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHLykFRNJTWE1EeRpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL2czN2MDM1ITM2ATMwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)