前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[Introduction]Go特殊的引用类型:值传递/指针传递/引用传递

[Introduction]Go特殊的引用类型:值传递/指针传递/引用传递

原创
作者头像
Wzy_CC
修改2020-08-10 14:36:44
1.5K0
修改2020-08-10 14:36:44
举报

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

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

代码语言:txt
复制
var a = 10
log.Printf("%p\n",a) // 变量地址假设为 0x00000001

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

指针/引用

指针变量存放其他变量的地址。在C++中引用就是变量的另一名字

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

值传递

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

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

指针传递

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

引用传递 for C++

在C++中的引用传递本质上将实参的地址传递到函数中,和指针传递效果类似

在Go中的函数调用只有值传递,但是存在引用类型slice、map、channel

代码语言:txt
复制
array := []int{1,2,3}
arrayslice := array[:]

GO中“特殊的引用类型”

能够通过make()创建的都是引用类型,比图slicemapslice本质上是一个指向数组内存空间的一个指针类型:

代码语言:txt
复制
type Slice struct {
    point Point // 内存地址
    len int
    cap int
}

所以本质上对slice切片的赋值,实质上就是对Slice这个结构体进行深拷贝,对于Point来说自然是指向同一段空间了。虽然是值传递,但是本质上是两个Slice对象,传递的对象是指针,指针相同,因此算是特殊的值传递。map同理

在Golang中的例子可以比较直观反应切片特性:

代码语言:txt
复制
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)
}

控制台输出:

代码语言:txt
复制
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,再次运行结果如下:

代码语言:txt
复制
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,验证:

代码语言:txt
复制
func main() {
    array := []int{1, 2, 3} // 数组
    log.Printf("array[0]:%p\n", &array[0])
}

控制台输出:

代码语言:txt
复制
2020/08/07 15:37:19 array[0]:0xc00000e3c0

arrayarray[0]的地址不一致。array[0]和其他切片的第零个元素的地址一样,继续尝试后可以得出结论:

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

**2.切片(结构体)的地址和切片首元素的地址是不一致的**,猜测声明切片的时候顺序是先创建了数组,然后初始化切片结构体为数组引用?

参考链接

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

我对变量产生了这些想法

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

理解 Golang 中 slice 的底层设计

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 变量名/变量值/变量地址
  • 指针/引用
  • 值传递
  • 指针传递
  • 引用传递 for C++
  • GO中“特殊的引用类型”
  • 参考链接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档