Golang - 指针与引用
? Golang有指针 , 那么一切数据都是值传递吗 ? 都需要用户进行指针传递吗, 其实不然, 对于Go语言, 虽然有指针, 但是其也有引用传递. 是不是很绕, 因为引用传递就是指针传递哇 . 我们继续解释.
概念
在Go语言中,对于布尔变量
或数值类型
或字符串类型
或数组
以及struct
都是按照值传递的:值在传递给函数或者方法时会被复制一份,然后方法或函数使用的是复制的这份值,也就不会对原值产生什么影响。一般情况下,对于布尔变量或数值类型或字符串类型的按值传递是非常廉价的,Go语言编译器会在传递过程中进行安全优化。
对于大字符串是这样,对于数组进行值传递也是如此。为了解决可能产生的巨大代价,Go语言使用数组切片来代替数组的使用。传递一个切片的代价跟传递字符串差不多,无论该切片的长度或容量是多大。对切片进行复制修改操作也不会像字符串那样需要创建新的切片,因为切片是可变的,属于引用类型
。
因此以下就是重点 :
语言中的值传递类型有:基本数据类型,数组 , struct
特点:变量直接存储值,内存通常在栈中分配,栈在函数调用完会被释放 , 在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数 , 所以他最大的好处就是不怕多线程安全性问题. 但是浪费内存
Go语言中的引用类型有:映射(map),数组切片(slice),通道(chan),接口(interface) 与 函数(func)。
他的变量默认就是指针变量, 所以不需要做&取地址. 你要是花里胡哨我也无语.
特点:变量存储的是一个地址,这个地址存储最终的值。内存通常在堆上分配,通过GC回收。所谓引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。引用注定多个线程中共享一个, 容易出现多线程问题,
就以引用传递和值传递区分 , 切记别被下面带绕了,这种话分析层面不同就不一样
其实在go语言中,只存在值传递,本质上,我们可以理解函数的传递都是值传递,只不过引用类型传递的是一个指向底层数据的指针,所以我们在操作的时候,可以修改共享的底层数据的值,进而影响到所有引用到这个共享底层数据的变量。
两大操作符
操作符& : 是返回该变量的内存地址。
操作符* :是返回该指针指向的变量的值,其实就是解除变量的指针引用,返回该变量的值.
空指针 :
当一个指针被定义后没有分配到任何变量时,它的值为 nil。
nil 指针也称为空指针。
nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。
认识指针
指针这个玩意, Java里没有,其实Java里确实有指针,我们无时无刻在使用,下面我举一个例子
type People struct { name string sex string age int } func main() { var pp *People // 1. 返回一个对象 person1 := People{"zhangsan", "man", 25} fmt.Println(person1) pp=&person1 // 2. 直接实例化一个空对象 , 返回一个指针对象 person2 := new(People) // pp=person2 fmt.Println(*pp) // 2.返回一个指针对象 person3 := &People{"wangwu", "man", 25} pp=person3 fmt.Println(*person3) fmt.Println(*pp) }
输出
{zhangsan man 25} { 0} {wangwu man 25} {wangwu man 25}
这里告诉大家一个技巧就是 fmt.Println()
输出中如果首位是 &
,那么它一定是一个指针类型的数据 . 但是对于默认的引用对象,不一定了,,,
函数传参是值传递 - 但是引用类型是指针传递, 不需要用户写*申明指针类型
举个例子 我们拿数组为例子 , 举例指针的用处
func main() { // 申明数组类型 arr := [3]int{1, 2, 3} // 原数组 fmt.Printf("指针 : %p , 数据 : %v\n", &arr,arr) // 地址传递 printSlice(&arr) // 值传递 printSlices(arr) // 原数组 fmt.Printf("指针 : %p , 数据 : %v\n", &arr,arr) } func printSlice(arr *[3]int) { // 修改数据 arr[0] = 5 fmt.Printf("指针 : %p , 数据 : %v\n", arr, *arr) } func printSlices(arr [3]int) { // 修改数据 arr[0] = 4 fmt.Printf("指针 : %p , 数据 : %v\n", &arr, arr) }
输出
指针 : 0xc000052140 , 数据 : [1 2 3] 指针 : 0xc000052140 , 数据 : [5 2 3] 指针 : 0xc0000521c0 , 数据 : [4 2 3] 指针 : 0xc000052140 , 数据 : [5 2 3]