結論:golang中函數傳參只有值傳遞html
var a = 10 log.Printf("%p\n",a) // 變量地址假設爲 0x00000001
變量名a,變量值10,變量地址0x00000001程序員
指針變量存放其餘變量的地址。在C++中引用就是變量的另外一名字golang
變量名自己並無做用,只至關於代號利於程序員編程,引用做爲別名本質上仍是指向同一個內存地址。指針本質上佔用一小段內存空間shell
值傳遞就是深拷貝,在函數內傳遞的副本,並不會影響函數外的實參編程
在函數調用時,將實參深拷貝後壓棧segmentfault
形參爲指向實參地址的指針,當對形參的指向操做時,就至關於對實參自己進行的操做數組
在C++中的引用傳遞本質上將實參的地址傳遞到函數中,和指針傳遞效果相似函數
在Go中的函數調用只有值傳遞,可是存在引用類型slice、map、channelpost
array := []int{1,2,3} arrayslice := array[:]
可以經過make()
建立的都是引用類型,比圖slice
和map
,slice
本質上是一個指向數組內存空間的一個指針類型:設計
type Slice struct { point Point // 內存地址 len int cap int }
因此本質上對slice
切片的賦值,實質上就是對Slice
這個結構體進行深拷貝,對於Point
來講天然是指向同一段空間了。雖然是值傳遞,可是本質上是兩個Slice
對象,傳遞的對象是指針,指針相同,所以算是特殊的值傳遞。map
同理
在Golang中的例子能夠比較直觀反應切片特性:
func printAddr(s []int) { // 打印數組地址 值參數 log.Printf("printAddr:%p\n", &s[0]) } func printAddrPoint(ps *[]int) { // 打印數組地址 指針參數 log.Printf("printAddrPoint:%p\n", &((*ps)[0])) } func main() { array := [3]int{1, 2, 3} // 數組 commit 1 // array := []int{1, 2, 3} // 切片 commit 2 log.Printf("array:%p\n", &array) arrayslice := array[:] // 切片 log.Printf("arrayslice:%p\n", &arrayslice) printAddr(arrayslice) printAddrPoint(&arrayslice) }
控制檯輸出:
2020/08/07 15:15:35 array:0xc00000e3c0 2020/08/07 15:15:35 arrayslice:0xc000004620 2020/08/07 15:15:35 printAddr:0xc00000e3c0 2020/08/07 15:15:35 printAddrPoint:0xc00000e3c0
本質上是由於切片傳遞依舊是值傳遞,雖然結構體自己不是一個地址,可是裏面包含的起始地址都是array[0]
這也能夠解釋爲何三者相同
註釋掉commit1,解註釋掉commit2,再次運行結果以下:
2020/08/07 15:22:42 array:0xc0000044a0 2020/08/07 15:22:42 arrayslice:0xc000004640 2020/08/07 15:22:42 printAddr:0xc00000e3c0 2020/08/07 15:22:42 printAddrPoint:0xc00000e3c0
猜想array[0]
的地址不出意外也應該是0xc00000e3c0
,驗證:
func main() { array := []int{1, 2, 3} // 數組 log.Printf("array[0]:%p\n", &array[0]) }
控制檯輸出:
2020/08/07 15:37:19 array[0]:0xc00000e3c0
array
和array[0]
的地址不一致。array[0]
和其餘切片的第零個元素的地址同樣,繼續嘗試後能夠得出結論:
1.數組地址等同於數組首元素地址,和C是一致的
2.切片(結構體)的地址和切片首元素的地址是不一致的,猜想聲明切片的時候順序是先建立了數組,而後初始化切片結構體爲數組引用?