
区别于C/C++中的指针,Go语言中的指针不能进行偏移和运算,是安全指针。
要搞明白Go语言中的指针需要先知道3个概念:指针地址、指针类型和指针取值。
很多人的理解可能以为指针是和spark中的游标一样,尤其是取数组中的值根据下标来取,其实不然,在这里,Go 语言中的指针所表示的是:一个指针变量指向了一个值的内存地址。类似于变量和常量,在使用指针前你需要声明指针。
任何程序数据载入内存后,在内存都有他们的地址,这就是指针。而为了保存一个数据在内存中的地址,我们就需要指针变量。
Go语言中的指针不能进行偏移和运算,因此Go语言中的指针 *** 作非常简单,我们只需要记住两个符号:
&(取地址)和*(根据地址取值)。
指针声明:var var_name *var-type //var-type 为指针类型,var_name 为指针变量名,* 号用于指定变量是作为一个指针。 var a *int // 指向整型 var b *float32 // 指向浮点型
指针(pointer)在Go语言中可以被拆分为两个核心概念:
类型指针,允许对这个指针类型的数据进行修改,传递数据可以直接使用指针,而无须拷贝数据,类型指针不能进行偏移和运算。切片,由指向起始元素的原始指针、元素数量和容量组成。 指针地址和指针类型每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go语言中使用&字符放在变量前面对变量进行“取地址” *** 作。 Go语言中的值类型(int、float、bool、string、array、struct)都有对应的指针类型,如:*int、*int64、*string等。
取变量指针的语法
ptr := &v // v的类型为T
其中:
v:代表被取地址的变量,类型为Tptr:用于接收地址的变量,ptr的类型就为*T,称做T的指针类型。*代表指针。指针使用流程:
定义指针变量。为指针变量赋值。访问指针变量中指向地址的值。在指针类型前面加上 * 号(前缀)来获取指针所指向的内容。
func main() { var a int= 20 /* 声明实际变量 */ var b *int /* 声明指针变量 */ b = &a /* 指针变量的存储地址 */ fmt.Printf("a 变量的地址: %x\n", &a ) /* 指针变量的存储地址 */ fmt.Printf("b 变量储存的指针地址: %x\n", b ) /* 使用指针访问值 */ fmt.Printf("*b 变量的值: %d\n", *b ) }
每个变量都拥有地址,指针的值就是地址。
空指针当一个指针被定义后没有分配到任何变量时,它的值为 nil。
nil 指针也称为空指针。
nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。
func main(){ var ptr *int fmt.printf("ptr的值为:%x\n",ptr) }
从指针获取指针指向的值
当使用& *** 作符对普通变量进行取地址 *** 作并得到变量的指针后,可以对指针使用* *** 作符,也就是指针取值
解析:
取地址 *** 作符&和取值 *** 作符*是一对互补 *** 作符,&取出地址,根据地址取出地址指向的值。变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
对变量进行取地址 *** 作使用& *** 作符,可以获得这个变量的指针变量。指针变量的值是指针地址。对指针变量进行取值 *** 作使用* *** 作符,可以获得指针变量指向的原变量的值。 指针取值和修改值在对普通变量使用& *** 作符取地址后会获得这个变量的指针,然后可以对指针使用* *** 作,也就是指针取值,
总结: 取地址 *** 作符&和取值 *** 作符*是一对互补 *** 作符,&取出地址,*根据地址取出地址指向的值。
变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
对变量进行取地址(&) *** 作,可以获得这个变量的指针变量。指针变量的值是指针地址。对指针变量进行取值(*) *** 作,可以获得指针变量指向的原变量的值。通过指针不仅可以取值,也可以修改值。
package main import "fmt" // 交换函数 func swap(a, b *int) { // 取a指针的值, 赋给临时变量t t := *a // 取b指针的值, 赋给a指针指向的变量 *a = *b // 将a指针的值赋给b指针指向的变量 *b = t } func main() { // 准备两个变量, 赋值1和2 x, y := 1, 2 // 交换变量值 swap(&x, &y) // 输出变量值 fmt.Println(x, y) //结果 2 1 }
解析:
定义一个交换函数,参数为 a、b,类型都为 int 指针类型。取指针 a 的值,并把值赋给变量 t,t 此时是 int 类型。取 b 的指针值,赋给指针 a 指向的变量。注意,此时a的意思不是取 a 指针的值,而是“a 指向的变量”。
将 t 的值赋给指针 b 指向的变量。
准备 x、y 两个变量,分别赋值为 1 和 2,类型为 int。
取出 x 和 y 的地址作为参数传给 swap() 函数进行调用。
交换完毕时,输出 x 和 y 的值。
* *** 作符作为右值时,意义是取指针的值,作为左值时,也就是放在赋值 *** 作符的左边时,表示 a 指针指向的变量。其实归纳起来,* *** 作符的根本意义就是 *** 作指针指向的变量。
当 *** 作在右值时,就是取指向变量的值,当 *** 作在左值时,就是将值设置给指向的变量。
new和makenew:
new是一个内置的函数
func new(Type) *Type
其中,
Type表示类型,new函数只接受一个参数,这个参数是一个类型*Type表示类型指针,new函数返回一个指向该类型内存地址的指针。new函数不太常用,使用new函数得到的是一个类型的指针,并且该指针对应的值为该类型的零值。
str := new(string) *str = "hello" fmt.Println(*str)
new() 函数可以创建一个对应类型的指针,创建过程会分配内存,被创建的指针指向默认值。
make:
make也是用于内存分配的,区别于new,它只用于slice、map以及chan的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了
func make(t Type, size ...IntegerType) Type
make函数是无可替代的,我们在使用slice、map以及channel的时候,都需要使用make进行初始化,然后才可以对它们进行 *** 作。这个我们在上一章中都有说明,关于channel我们会在后续的章节详细说明。
比如:var b map[string]int只是声明变量b是一个map类型的变量,需要像下面的示例代码一样使用make函数进行初始化 *** 作之后,才能对其进行键值对赋值
make和new的区别 二者都是用来做内存分配的。make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身;而new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针。欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)