實例學習Golang--defer

 Go語言的 defer 語句會把它後面的語句記錄下來,多個defer的語句記錄時像一個壓棧的操作,

在 defer 歸屬的函數即將返回時,將記錄的語句按 defer 的逆序進行執行,

也就是說,最後被 defer 的語句,最先被執行,類似出棧。

在業務處理中,打開和關閉文件、接收請求和回覆請求、加鎖和解鎖等操作,

      defer 語句正好是在函數退出時執行的語句,所以使用 defer 能非常方便地處理資源釋放問題。

可以利用defer語句的特性,防止資源沒有被釋放。

看到一個面試題,就是不好好用defer 語句,非要花裏胡哨的......但是對於理解defer 執行順序挺有用。

package main

import "fmt"

// defer 在函數中的流程是:
// 1, 記錄defer語句(不執行)
// 2, return 語句給返回值賦值
// 3, 執行 defer語句
// 4, 底層RET指令
func f1() int {
	x := 5
	defer func() {
		x++
	}() // 立即執行函數
	return x
}  // 1, 返回值沒有指定變量, return x 賦值爲 5,可以理解爲開闢了一個沒有命名的內存把x的值給了它,存的值是 5
   // 2, defer中x++ 修改的是x, 不是返回值,
   // 3, 執行RET 真正返回的是 5 

func f2() (x int) {
	defer func() {
		x++
	}()
	return 5
}  // 1, 返回值爲 x 已確定, return 5 == x
   // 2, defer 執行 x++,修改了x的值, 
   // 3, RET x, 此時 x == 6

func f3() (y int) {
	x := 5
	defer func() {
		x++
	}()
	return x
}  // 1, 返回值爲 y 已確定,return 的 x = y = 5
   // 2, defer 執行 x++, 修改的是x, 不是返回值 (x 的值賦給 y, 然後再去修改 x, 跟 y 是沒有關係的)
   // 3, 真正RET = y = 5

func f4() (x int) {
	defer func(x int) {
		x++
	}(x)
	return 5
}  // 1, 返回值爲 x 已確定,return 的 5 = x,
   // 2, defer 函數x作爲參數,執行 x++, defer匿名函數中的x 和返回值不是一個x,只是x的值作爲參數去defer的函數中溜達了一圈,是x的值,不是x
   // 3, 真正RET的一個變量值爲 5

func f5() (x int) {
	defer func(x int) int {
		x++
		return x
	}(x)
	return 5
}  // 1, 返回值爲 x 已確定,return 的 5 = x, 
   // 2, defer 函數x作爲參數返回值爲int型, 執行 x++, defer匿名函數中的x 和返回值同樣不是一個x,而且這個defer的匿名函數的返回值並沒有被接收
   // 3,所以真正返回的值還是 5

func f6() (x int) {
	defer func(x *int) {
		(*x)++
	}(&x)

	return 5
} // 1, return 5, 此時 x = 5, 
  // 2, defer語句執行,傳入的是x的地址,在內存地址中修改了返回值x, x==6
  // 3, 函數int型返回值 訪問 x 時, x 的地址存的是 6,所以 真正 RET 爲 6

func main() {
	fmt.Println(f1()) // 5
	fmt.Println(f2()) // 6
	fmt.Println(f3()) // 5
	fmt.Println(f4()) // 5
	fmt.Println(f5()) // 5
	fmt.Println(f6()) // 6
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章