golang中指针,new和make函数作用
Posted Leo Han
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang中指针,new和make函数作用相关的知识,希望对你有一定的参考价值。
我们知道golang中的传递都是基于值传递,如果一个结构体比较大,这时候值传递需要复制的内容就比较多同时由于是基于值复制,耗费空间和时间,另外,基于值传递我们在调用的函数中对传入的参数进行修改,对于原值是没有任何影响的,也就是我们无法在函数中对传入的参数的原值进行修改
因此golang中提供了指针,和c、c++中的指针的概念类似,这时候传递的是指针,也是值复制,但是复制的是指针(指针比较小),这样我们既能够快速的将参数传递过去,同事也能够对原值进行修改。
需要注意的是,golang中存在另种内存模块,即我们常说的堆和栈,函数一般在栈上运行,局部变量在栈上分配,当函数结束之后,函数栈被回收,但是golang运行时会判断如果这个局部变量在函数结束之后还有其他区域引用,则会在栈上分配:
func testHeap() *model.JobInfo
jobInfo := model.JobInfo
return &jobInfo
这段代码如果在C中是会出问题的,因为C中函数结束之后,除非是显示调用maclloc在堆上分配空间,在栈上分配的都会被回收,返回的地址空间内容将不可知。
但是在golang中是可以运行的,因为golang运行时会自动判断外部是否还需要引用,如果需要引用这个的话,那么这个变量就不会在栈上分配,而是在堆上分配,golang的垃圾回收的作用区间也是在堆上。
指针是一种数据类型,其存储的是一个内存地址,该地址指向一个实际的内存单元
golang中声明指针一般如下:
var ptrName *prtType
var strPtr *string
这样我们就声明了一个类型为*string
的指针,这时候strPtr
的内容实际上是nil,而对指针变量赋值需要用到&
取地址运算符:
var strPtr *string
str := "hello world"
strPtr = &str
fmt.Println(*strPtr)
而如果我们要获取指针对应的实际内容,需要用到取内容运算符*
:
// 打印 0xc000038790
fmt.Println(strPtr)
// 打印 hello world
fmt.Println(*strPtr)
可以看到,打印指针变量的值对应的是一个地址,而取改地址的内容则是实际的值。
指针是可以有多个结合的,指向指针的指针:
intVal := 10
var intPtr *int
var intPtrPtr **int
intPtr = &intVal
intPtrPtr = &intPtr
fmt.Println("intPtrPtr = ",intPtrPtr)
fmt.Println("*intPtrPtr = ",*intPtrPtr)
fmt.Println("intPtr = ",intPtr)
fmt.Println("**intPtrPtr = ",**intPtrPtr)
fmt.Println("*intPtr = ",*intPtr)
打印如下:
intPtrPtr = 0xc0000d8020
*intPtrPtr = 0xc0000ac970
intPtr = 0xc0000ac970
**intPtrPtr = 10
*intPtr = 10
还可以更多的指针结合:
var intPtrPtr ***int
指向数组的指针:
var ptrArr [3]*int
指向结构体的指针
指向结构体的指针我们可以使用两种方式来进行初始化,一种是使用&
取地址运算符,另外一种是使用new
运算符:
var jobPtr *model.JobInfo
jobInfo := model.JobInfo
jobPtr = &jobInfo
jobPtr = new(model.JobInfo)
jobPtr.Id = 12345
一般我们通过new和make来创建指针,一般而言
- new 函数只用于分配内存,并且将内存清零(c、c++不会清零),返回一个对应类型的零值的指针
- make只用于slice、chan、map这三种内置类型的创建和初始化
以上是关于golang中指针,new和make函数作用的主要内容,如果未能解决你的问题,请参考以下文章