GO的指针传递
Go里只有值传递,没有引用传递
因为拷贝的内容有时候是非引用类型(int、string、struct等这些),这样就在函数中就无法修改原内容数据;有的是引用类型(指针、map、slice、chan等这些),这样就可以修改原内容数据。
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
}
原始指针的内存地址是:0xc42000c028
函数里接收到的指针的内存地址是:0xc42000c038
int值被修改了,新值为: 1
引用传递
golang 没有引用传递,在上例中,如果是引用传递则内存地址不会发生改变,均为0xc42000c028。
字符串、数组、slice的传递
三者的底层原始数据有相同的内存结构。
数组:
- 可修改数组元素
- 数组的赋值和函数传参都是以整体复制的方式处理的。
字符串:
- 字符串的只读属性禁止程序中对底层字节数组的元素进行修改
字符串的赋值和传参只复制数据地址和对应长度,而不会导致底层数据的复制
type stringStruct struct {
str unsafe.Pointer
len int
}
slice:
可以修改数组元素
slice赋值和传参时将slice片头的指针按值传递的方式处理
type slice struct {
array unsafe.Pointer
len int
cap int
}
map
可以修改数组元素
type hmap struct {
// Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.
// Make sure this stays in sync with the compiler's definition.
count int // # live cells == size of map. Must be first (used by len() builtin)
flags uint8
B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
hash0 uint32 // hash seed
buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
extra *mapextra // optional fields
}