乐趣区

关于golang:IntroductionGo特殊的引用类型值传递指针传递引用传递

论断:golang 中函数传参只有值传递

变量名 / 变量值 / 变量地址

var a = 10
log.Printf("%p\n",a) // 变量地址假如为 0x00000001

变量名 a,变量值 10,变量地址 0x00000001

指针 / 援用

指针变量寄存其余变量的地址。在 C ++ 中援用就是变量的另一名字

变量名自身并没有作用,只相当于代号利于程序员编程,援用作为别名实质上还是指向同一个内存地址。指针实质上占用一小段内存空间

值传递

值传递就是深拷贝,在函数内传递的正本,并不会影响函数外的实参

在函数调用时,将实参深拷贝后压栈

指针传递

形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参自身进行的操作

援用传递 for C++

在 C ++ 中的援用传递实质上将实参的地址传递到函数中,和指针传递成果相似

在 Go 中的函数调用只有值传递,然而存在援用类型 slice、map、channel

array := []int{1,2,3}
arrayslice := array[:]

GO 中“非凡的援用类型”

可能通过 make() 创立的都是援用类型,比图 slicemapslice实质上是一个指向数组内存空间的一个指针类型:

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

arrayarray[0] 的地址不统一。array[0]和其余切片的第零个元素的地址一样,持续尝试后能够得出结论:

1. 数组地址等同于数组首元素地址,和 C 是统一的

2. 切片 (构造体) 的地址和切片首元素的地址是不统一的,猜想申明切片的时候程序是先创立了数组,而后初始化切片构造体为数组援用?

参考链接

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

我对变量产生了这些想法

Golang 中函数传参存在援用传递吗?

了解 Golang 中 slice 的底层设计

退出移动版