函數傳遞機制
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