GO的指针传递

Go里只有值传递,没有引用传递
因为拷贝的内容有时候是非引用类型(int、string、struct等这些),这样就在函数中就无法修改原内容数据;有的是引用类型(指针、map、slice、chan等这些),这样就可以修改原内容数据。

  1. func main() {
  2. i:=10
  3. ip:=&i
  4. fmt.Printf("原始指针的内存地址是:%p\n",&ip)
  5. modify(ip)
  6. fmt.Println("int值被修改了,新值为:",i)
  7. }
  8. func modify(ip *int){
  9. fmt.Printf("函数里接收到的指针的内存地址是:%p\n",&ip)
  10. *ip=1
  11. }
  1. 原始指针的内存地址是:0xc42000c028
  2. 函数里接收到的指针的内存地址是:0xc42000c038
  3. int值被修改了,新值为: 1

引用传递

golang 没有引用传递,在上例中,如果是引用传递则内存地址不会发生改变,均为0xc42000c028。

字符串、数组、slice的传递

三者的底层原始数据有相同的内存结构。
数组:

  • 可修改数组元素
  • 数组的赋值和函数传参都是以整体复制的方式处理的。

字符串:

  • 字符串的只读属性禁止程序中对底层字节数组的元素进行修改
  • 字符串的赋值和传参只复制数据地址和对应长度,而不会导致底层数据的复制

    1. type stringStruct struct {
    2. str unsafe.Pointer
    3. len int
    4. }

    slice:

  • 可以修改数组元素

  • slice赋值和传参时将slice片头的指针按值传递的方式处理

    1. type slice struct {
    2. array unsafe.Pointer
    3. len int
    4. cap int
    5. }

    map

  • 可以修改数组元素

  1. type hmap struct {
  2. // Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.
  3. // Make sure this stays in sync with the compiler's definition.
  4. count int // # live cells == size of map. Must be first (used by len() builtin)
  5. flags uint8
  6. B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
  7. noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
  8. hash0 uint32 // hash seed
  9. buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
  10. oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
  11. nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
  12. extra *mapextra // optional fields
  13. }

参考

Go语言参数传递是传值还是传引用