golang: defer的調用順序

golang中的defer關鍵字指明,其後面的函數將在defer所在作用域的函數返回後,自動調用。只能是函數,不能是其他形式的表達式,如果要執行表達式,可以加一個匿名函數,且無返回值。形如:

func Foo(){
	fmt.Println("defer call...")
}
func DeferCall(){
	defer Foo()
	defer func(){
		fmt.Println("anonymous defer call...")
	}()
}

當函數中有多個defer時,註冊的函數調用的順序: 先註冊後調用,後註冊先調用。跟入棧出棧的順序一樣。

有如下面試題:

package main

import "fmt"

func cacl(s string, a, b int) int {
	ret := a + b
	fmt.Println(s, a, b, ret)
	return ret
}

func main() {

	a := 1
	b := 2
	defer cacl("10", a, cacl("11", a, b))	// defer1
	a = 0
	defer cacl("20", a, cacl("22", a, b)) // defer2
	b = 1
}

執行結果:

11 1 2 3
22 0 2 2
20 0 2 2
10 1 3 4

解釋:
在defer1時,註冊的是前面一個cacl,後面一個cacl並不是註冊到defer的。因此在進入main函數執行到defer時,會先調用後一個cacl,獲得返回值後,將此值作爲參數,傳遞給前一個cacl。此時參數1和參數2也拷貝一份並保存在函數棧中。defer2也是如此。在main函數返回後,根據先註冊後調用,後註冊先調用的規則,將先執行cacl("20", 0, 2), 再執行cacl("10", 1, 3)。注意:a,b的值都是值傳遞,因此,再a,b的值更改後,並不影響已經註冊cacl的參數的值。

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