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

智码漫游家
• 阅读 3102

结论: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 的底层设计

点赞
收藏
评论区
推荐文章
似梦清欢 似梦清欢
4年前
Linux shell(2)
1.变量以固定名称存放的可能变化的值,可以提高脚本的适应能力,方便脚本执行中重复使用某个值。定义/赋值变量格式为:变量名变量值注意事项:若指定变量已存在,则相当于重新给变量赋值;等号两边无空格;变量名区分大小写;变量名不能以数字开头,不使用关键字和特殊字符。root@localhostX1//定义变量
LinMeng LinMeng
4年前
vue中页面间跳转传值的两种方式(query,params)
两者都可以传递参数,区别是什么?query传参配置的是path,而params传参配置的是name,在params中配置path无效query在路由配置不需要设置参数,而params必须设置query传递的参数会显示在地址栏中params传参刷新会无效,但是query会保存传递过来的值,刷新不变;query:this.$route
Kevin501 Kevin501
4年前
Go语言中new()和make()的区别
1.Go语言中的值类型和引用类型值类型:int,float,bool,string,struct和数组(数组要特别注意,别搞混了)变量直接存储值,分配栈区的内存空间,这些变量所占据的空间在函数被调用完后会自动释放。引用类型:slice,map,chan和值类型对应的指针变量存储的是一个地址(或者理解为指针),指针指向内存中真
Wesley13 Wesley13
3年前
Java中只存在值传递
在Java中并不存在引用传递(即地址传递),对于变量(可以是基本数据类型,也可以是引用数据类型)而言,可以理解为就是一个地址。传递,存在着拷贝操作。举个列子:1、在方法参数上,传递的是基本数据类型。定义了一个用于交换两个整型数的方法:publicstaticvoidswap(inta,intb){in
Wesley13 Wesley13
3年前
Java对象的浅拷贝和深拷贝&&String类型的赋值
Java中的数据类型分为基本数据类型和引用数据类型。对于这两种数据类型,在进行赋值操作、方法传参或返回值时,会有值传递和引用(地址)传递的差别。浅拷贝(ShallowCopy):①对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,
Wesley13 Wesley13
3年前
Java里的按值传递与引用传递
按值传递还是按引用传递这个在Java里面是经常被提起的问题,也有一些争论,似乎最后还有一个所谓的结论:“在Java里面参数传递都是按值传递”。事实上,这很容易让人迷惑,下面先分别看看什么是按值传递,什么是按引用传递,只要能正确理解,至于称作按什么传递就不是个大问题了。1:按值传递是什么指的是在方法调用时,传递的参
Stella981 Stella981
3年前
26 函数形参值回传问题——C++解决多个return的一般方法
0引言在使用数组和vector作为函数的参数进行参数传递并希望得到值的回传时,由于不知道怎么写数组函数形参的引用形式,一直采用vector的引用形式。但是,刚刚测试了一下,发现数组作为参数本身就是指针,根本不需要采用引用形式把值回传啊,把测试结果写下来。1 关于数组作为函数参数的值传递问题——数组和容器的对比  数组直接作为
Wesley13 Wesley13
3年前
Java只有值传递(Java值传递还是引用传递?)
转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10830521.html(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fwww.cnblogs.com%2Fygj0930%2Fp%2F10830521.html)一:区分Java数据类型、变
Wesley13 Wesley13
3年前
Java面试中的值传递与引用传递
一、前言Java是值传递的,对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量。对于对象型变量而言的,传递的是该对象地址的一个副本,,并不是原对象本身,这里也有人说是引用传递。由于副本的地址和原对象地址一致,因此对副本的值进行操作时,会同步改变原对象值。_但是一旦副本的地址被改变,副本的值的操作则不会影响原对象地址。(
Easter79 Easter79
3年前
Swift3.0 类和结构体的选择
结构体实例总是通过值传递,类实例总是通过引用传递先说说值类型和引用类型的区别值类型被赋予给一个变量、常量或者被传递给一个函数的时候,其值会被拷贝在Swift中,所有的结构体和枚举类型都是值类型。这意味着它们的实例,以及实例中所包含的任何值类型属性,在代码中传递的时候都会被复制。引用类型在被赋予到一个变量、常
九路 九路
2年前
C++之值传递&指针传递&引用传递详解
C之值传递&指针传递&引用传递详解目录C之值传递&指针传递&引用传递详解(about:blankc%E4%B9%8B%E5%80%BC%E4%BC%A0%E9%80%92%E6%8C