Go參數傳遞
在面試中,經常會被問起,這門語言的參數傳遞是值傳遞還是引用傳遞,當然,大部分情況下我們都會提前准備,有恃無恐,但還是希望能夠精益求精嘛,所以針對Go語言來分析,Go傳參是值傳遞還是引用傳遞。那首先,我們先來了解什么是值傳遞,什么是引用傳遞。
值傳遞
值傳遞就是函數傳遞的是傳進來參數的一個副本。換個說法就是函數內部修改傳入參數的值是函數外部傳入值得一個拷貝,所以你在函數內部對這個值進行修改也不會影響外部該參數的值,的確很難表達,看個案例:
package main
import "fmt"
func modify(a int){
a = 10
}
func main(){
a := 20
fmt.Println(a)
modify(a)
fmt.Println(a)
}
輸出:
20
20
很直觀,參數a在進入函數后並沒有被改變,我們還可以看看兩個內存地址是否相同
package main
import "fmt"
func modify(a int){
fmt.Println(&a)
a = 10
}
func main(){
a := 20
fmt.Println(&a)
modify(a)
}
輸出為:
0xc000052080
0xc000052088
可以看到兩個內存地址並不一樣,這就對了,可以說明modify
中的參數a,並不是主函數中的變量a,而是a的一個拷貝而已,所以在函數中修改的也是拷貝a的值,對函數外的這個a並沒有改動。
這個時候,我們就會使用指針來修改值,指針案例:
func main() {
i:=10
ip:=&i
fmt.Printf("原始指針的內存地址是:%p\n",&ip)
modify(ip)
fmt.Println("int值被修改了,新值為:",i)
}
func modify(ip *int){
fmt.Printf("函數里接收到的指針的內存地址是:%p\n",&ip)
*ip=1
}
輸出:
原始指針的內存地址是:0xc000006028
函數里接收到的指針的內存地址是:0xc000006038
int值被修改了,新值為: 1
可以看到兩次內存地址也是不一樣的,所以其實指針也是值傳遞,但是指針保存的是內存地址,而在函數中修改語句"*ip=1",其實是在修改變量i內存地址對應的值,那自然就是能夠修改的。
引用傳遞
Go語言其實並沒有引用傳遞,上面的例子可以證明如果內存地址不同自然就是值傳遞,那內存地址相同就是引用傳遞。
我們再通過Map類型進行驗證,Map類型可以通過函數修改內容,但是他沒有明顯的指針。
func modify(p map[string]int){
fmt.Printf("函數里接收到map的內存地址是:%p\n",&p)
p["張三"] = 20
}
func main(){
person := make(map[string]int)
person["張三"] = 56
fmt.Printf("原始map的內存地址是:%p\n",mp)
modify(person)
fmt.Println("map值被修改了,新值為:",person)
}
輸出:
原始map的內存地址是:0xc00007e018
函數里接收到map的內存地址是:0xc00007e028
map值被修改了,新值為: map[張三:20]
發現兩個內存地址是不一樣的,所以這又是一個值傳遞,那為什么沒有使用指針卻修改了Map的內容?
查看一下map源碼
func makemap(t *rtype, cap int) (m unsafe.Pointer)
我們發現這個方法返回的是m unsafe.Pointer
繼續查看一下unsafe.Pointer
類型是什么?
type Pointer *ArbitraryType
返回的還是一個指針,所以我們可以得出map的傳遞也是值傳遞。
結論
確認Go語言中所有的傳參都是值傳遞。但是傳遞的類型如果是int、string、struct等這些,那在函數中無法修改原參數內容數據;如果是指針、map、slice、chan等這些,在函數中可以修改原參數內容數據。