go語言defer語句實踐

func main() {
	// 在打開資源後關閉的時候通常會用到defer,例如關閉打開的文件它能確保你不會忘記關閉文件。
	readFile()
	// 被推遲執行的函數,如果有實參傳入該函數,那麼該實參會在**推遲執行**的時候就會計算,而不是在**實際執行**的時候計算,例如:
	calcA()
	// defer的執行順序是LIFO 先入後出
	calcB()
	// defer 與return的執行順序,輸出結果爲0 1,可以看出先執行return後面的方法,再執行的defer後面的方法
	// defer、return、返回值三者的執行邏輯應該是:return最先執行,return負責將結果寫入返回值中;接着defer開始執行一些收尾工作;最後函數攜帶當前返回值退出。
	deferReturn(0)
	// defer 推遲執行的方法,實參是指針,改變參數的值會影響defer後面函數的執行,因爲defer的時候實參實際上是一個指針地址
	a := &ask{a: 1}
	deferReturn2(a)

1.defer常用來關閉打開的資源

// readFile defer常用來關閉打開的文件
func readFile() error {
	f, err := os.Open("README.md")
	if err != nil {
		return err
	}
	defer f.Close()

	content, err := ioutil.ReadAll(f)
	if err != nil {
		return err
	}
	fmt.Printf("%s", content)

	return nil
}

2.defer推遲執行的函數的實參

// calcA 被推遲函數的實參(如果該函數爲方法則還包括接收者)在推遲執行時就會求值, 而不是在調用執行時才求值。
func calcA() {
	a, b := 1, 2
	defer fmt.Println(sum(a, b))
	defer fmt.Println(a)

	a, b = 3, 4
	fmt.Println(sum(a, b))
}

3.defer的調用順序

// calcB 被推遲的函數按照後進先出(LIFO)的順序執行。所以會輸出結果是 7 3
func calcB() {
	a, b := 1, 2
	defer fmt.Println(sum(a, b))

	c, d := 3, 4
	defer fmt.Println(sum(c, d))
}

func sum(a, b int) int {
	return a + b
}

4.defer和return的執行順序

func printA(a int) int {
	fmt.Println(a)
	return a
}

// deferReturn defer和return的執行順序,輸出結果爲0 1,可以看出先執行return後面的方法,再執行的defer後面的方法
func deferReturn(a int) int {
	defer printA(a + 1)
	return printA(a)
}

5.defer推遲執行的函數參數爲指針類型時

type ask struct {
	a int
}

func printAsk(a *ask) {
	fmt.Println(a.a)
}

// deferReturn2 輸出結果是1 10,說明defer推遲執行的方法的參數如果是一個指針類型,在defer之後對參數值進行修改,會影響到defer後面的方法實際執行時參數的內容
func deferReturn2(a *ask) {
	printAsk(a)
	defer printAsk(a)
	a.a = 10
}

6.defer函數執行的值有可能會影響return的值

https://my.oschina.net/henrylee2cn/blog/505535

7.defer的作用域

  1. defer只對當前協程有效(main可以看作是主協程);
  2. 當panic發生時依然會執行當前(主)協程中已聲明的defer,但如果所有defer都未調用recover()進行異常恢復,則會在執行完所有defer後引發整個進程崩潰;
  3. 主動調用os.Exit(int)退出進程時,已聲明的defer將不再被執行。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章