Go學習隨筆(八)函數參數傳遞機制\defer和跟蹤語句

函數傳遞機制

func add(a int) int {
	a++
	return a
}

func addo(a *int) int {
	*a++
	return *a
}

func main() {
	x := 3
	fmt.Println("x=", x, " &x=", &x)

	y := add(x)   //執行add實際上修改的是x的副本
	fmt.Println("x=", x, " y=", y)  //輸出的還是x原來的值,改變的是副本y

	z := addo(&x)  //執行addo函數,實際上修改的是x的值
	fmt.Println("x=", x, " z=", z)  //輸出的x已經被修改
	fmt.Println("&x=", &x)    //x的地址還是原來的
}

結果:
x= 3  &x= 0xc0000140a8
x= 3  y= 4
x= 4  z= 4
&x= 0xc0000140a8

 傳指針最明顯的三點好處:

1.傳指針使得多個函數能操作同一個對象

2.傳指針比較輕量級(8B),畢竟只傳遞內存地址,可以用指針傳遞體積大的結構體。如果傳遞值,在每次創建副本上面就會花費相對較多的系統開銷(內存和時間),所以當傳遞較大的結構體時候,用指針是一個明智的選擇。

3.傳遞指針給函數不但可以節省內存(因爲沒有複製變量的值),而且賦予了函數直接修改外部變量的能力,所以被修改的變量不在需要使用 return 返回。

 

func main() {
	n := 0
	res := &n
	muliply(2, 4, res)
	fmt.Println("Result:", *res)
	fmt.Println("n的地址:", &n)
	fmt.Println("n的值:", n)
	fmt.Println("res直接打印:", res)
	fmt.Println("res的地址:", &res)
}

func muliply(a, b int, res *int) {
	*res = a * b
}

 res是一個指向int變量的指針,通過這個指針,在函數內修改了這個int變量的值。

defer與跟蹤

 defer延遲語句可以在函數中添加多個,當函數執行到最後(return語句執行之前),這些defer語句會按照後進先出的順序執行(類似棧,先進後出)。

 舉個方便的小例子:

func ReadWrite()bool{
    file.Open("file")  
    defer file.Close()   //文件打開和關閉都放在一起寫不容易遺漏。其他語言可能得寫兩句,而且關閉是之後的操作,可能造成遺忘出錯
}

先進後出類似棧的進出

func main() {
	for i:=0;i<5;i++{
		defer fmt.Println(i)
	}
}

結果:
4
3
2
1
0

關於defer,return和返回值之間的執行順序

1.函數值被命名

func a() int {
	var i = 1
	defer func() {
		i++
		fmt.Println("defer2:", i)
	}()
	defer func() {
		i++
		fmt.Println("defer1:", i)
	}()
	return i
}
結果:
defer1: 2
defer2: 3
return: 1

2.有命名返回值情況下

 

func main() {
	fmt.Println("return:", b())
}

func b() (i int) {
	defer func() {
		i++
		fmt.Println("defer2:", i)
	}()
	defer func() {
		i++
		fmt.Println("defer1:", i)
	}()
	return i
}

結果:
defer1: 1
defer2: 2
return: 2

跟蹤

defer經常用於代碼跟蹤

func trace(s string)string{
    fmt.Println("開始執行:", s)
    return s
}

func un(s string){
    fmt.Println("結束執行:", s)
}

 

func main() {
	b()
}

func a() {
	defer un(trace("a")) //初始化defer函數的參數,所以輸出trace()的結果
	fmt.Println("a的邏輯代碼")
}

func b() {
	defer un(trace("b"))
	fmt.Println("b的邏輯代碼")
	a()
}

func trace(s string) string {
	fmt.Println("開始執行:", s)
	return s
}

func un(s string) {
	fmt.Println("結束執行:", s)
}


結果:
開始執行: b
b的邏輯代碼
開始執行: a
a的邏輯代碼
結束執行: a
結束執行: b

 

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