Go中都是值传递
我看在技术大群里面有人问我,到底值类型,引用类型以及指针类型有什么区别?为什么别人说函数传参是引用传递或者值传递,有的人说是指针传递?
想要彻底搞清楚这个问题,你得先通过表现来理解一下,然后在深入源码理解下你很快就会明白的。
所以网上说的有可能都是错误的,大家千万别被误导!
我们接下来重点解决函数传递参数到底是值传递还是其他类型传递!
三者区别
- 值类型 就是变量赋值的时候将直接获得一个真实的数据副本,请大家再次看清楚,真实的"数据"副本。比如
var int a = 10,b:=a
这就相当于a持有10,b持有a的数据的副本 那就将10拷贝到b指向的内存。 - 引用类型 就是仅仅是把对象的引用赋给变量,这样就可能导致多个变量引用到一个实际对象实例上。比如
a := make([]int, 0),b:=a[2:]
,那么a和b持有的就是底层对象的引用,说白了a和b就是底层对象的别名。 - 指针类型 就是赋给变量的是一个内存地址,这个地址指向真实的数据,比如
var int a = 10,p:=&a
,这个p就是指针变量,它存储的就是a的地址。
注意:在Go中弱化了指针,所以一般只需要关注值和引用类型就可以。
函数传参
首先声明一点:在Go中除了slice
,map
,channel
类型之外的变量都是值类型。
那就好说了,引用类型就三种:slice, map和channel
,其他都是值类型。
在Go中引用类型的变量初始化默认是make
,但是new
也是可以的,比如:
package main import "fmt" type A []int func main() { a := new(A) *a = append(*a, 1) fmt.Println(*a) //[1] a1 := make([]int, 0) a1 = append(a1, 1) fmt.Println(a1) //[1] }
当然map
以及channel
也是可以用make
和new
的,大家下去试试哈。
至于make
和new
的区别大家下去自己看哈,这不是本文的重点。
接下来我们重点来聊聊函数传参的问题,我们都知道值传递是copy一份,所以这个大家都能理解,我们重点讲解大家疑惑的问题,引用类型的传参问题。
首先大家看一个例子,即看看它的表现是什么:
package main import "fmt" func CopyList(a []int) { a = append(a, 2) fmt.Printf("copylist is %p \n", &a) fmt.Println("copylist value is ", a) } func main() { a := make([]int, 0) a = append(a, 1) fmt.Println("main value is ", a) fmt.Printf("main address is %p \n", &a) CopyList(a) } 输出: main value is [1] main address is 0xc0000a6018 copylist is 0xc0000a6048 copylist value is [1 2]
我们通过结果分析下引用传递会有什么影响。
- 首先函数参数是
a []int
- main中定义的引用类型变量是
a
并且也做了初始化- 然后调用
CopyList(a)
- 看在main中a的地址和在CopyList中a的地址,发现不一样?为什么不一样呢?因为Go语言在设计的时候明确表示
函数参数传递是值传递
,所以相当于函数CopyList拷贝了一份变量,这个时候次a非比a。但是那你可能说:为什么拷贝了一份,但是从结果来看就是引用啊,因为函数CopyList改变了外面main中a的值。
答案就是Go在设计引用类型的时候,比如这三者map,slice和channel
,他们的结构体中并没有直接保存数据,而是保存了指向数据的指针,那么在函数中传递这三种的变量其实只是拷贝了一份它们自己的一份结构体,但是结构体里面具体保存的指针指向的地址还是同一份,没有变化的。所以这也就说明函数中为什么可以改变引用类型变量的值了,因为底层指针指向的地址是同一个。
分析完了slice
,其它两个都比较简单,这里就不再演示了,大家下去自己尝试。
type slice struct { array unsafe.Pointer //指针 到时候slice初始化的时候会用mallocgc分配内存,把这块内存地址保存到array中。 len int cap int }
map和channel
里面也是有指针,指向一块内存空间。
小结
大家一定要记住在Go中函数传递参数一定是值传递,千万别搞混淆了,至于为什么上面也说清楚了,如果大家还不懂就进群,大牛比较多为你继续解惑哈。
- END -