go可以看成增強(qiáng)版的C語(yǔ)言街佑,因此也在一定程度上延續(xù)了C的一些特性愉棱。和C一樣Go語(yǔ)言的函數(shù)調(diào)用參數(shù)全部是傳值的翎蹈,包括 slice/map/chan 在內(nèi)所有類型分别,沒(méi)有傳引用的說(shuō)法遍愿,傳指針也是將指針的值拷貝一份。
那Go語(yǔ)言有傳引用的說(shuō)法嗎?
Go語(yǔ)言其實(shí)也是有傳引用的地方的耘斩,但是不是函數(shù)的參數(shù)沼填,而是閉包對(duì)外部環(huán)境是通過(guò)引用訪問(wèn)的。
func main() {
a := new(int)
fmt.Println(a)
func() {
a = nil
}()
fmt.Println(a)
}
輸出
0xc42000a3c8
<nil>
因?yàn)殚]包是通過(guò)引用的方式使用外部環(huán)境的a變量, 因此可以直接修改a的值.
比如下面2段代碼的輸出是截然不同的, 原因就是第二個(gè)代碼是通過(guò)閉包引用的方式輸出i變量:
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
// Output: 4 3 2 1 0
}
fmt.Printf("\n")
for i := 0; i < 5; i++ {
defer func(){ fmt.Printf("%d ", i) } ()
// Output: 5 5 5 5 5
}
像第二個(gè)代碼就是于閉包引用導(dǎo)致的副作用, 回避這個(gè)副作用的辦法是通過(guò)參數(shù)傳值或每次閉包構(gòu)造不同的臨時(shí)變量:
// 方法1: 每次循環(huán)構(gòu)造一個(gè)臨時(shí)變量 i
for i := 0; i < 5; i++ {
i := i
defer func(){ fmt.Printf("%d ", i) } ()
// Output: 4 3 2 1 0
}
// 方法2: 通過(guò)函數(shù)參數(shù)傳參
for i := 0; i < 5; i++ {
defer func(i int){ fmt.Printf("%d ", i) } (i)
// Output: 4 3 2 1 0
}
我是咕咕雞煌往,一個(gè)還在不停學(xué)習(xí)的全棧工程師。
熱愛(ài)生活轧邪,喜歡跑步刽脖,家庭是我不斷向前進(jìn)步的動(dòng)力。