golang中一个十分显明的特点就是引入了指针的应用,这个在py、php、java中都是不反对的,然而很多读者都反馈说对指针不是很理解,所以明天写了这篇文章,当然我尽量用艰深的语言,心愿对您有用。
什么是指针
想理解什么是指针,你先得理解数据是怎么取到的
func main() { var a int a = 1 fmt.Println("a的值为", a)}
上述代码非常简单,我置信不会golang的读者应该也能看懂。然而他底层到底干嘛了?你真的理解过么?接下来咱们逐个解释
var a int
首先这一步,是给变量a,在内存中开拓了一块空间,因为是int类型,所以空间大小为4个字节,那么问题来了,这块空间开在内存哪个地位? 首先这块地位是零碎随机调配的一块。另外给这块内存做了一个标记,不便下次找到,这个标记就在这块内存的起始的地位
a = 1
接下来给变量a赋值为1。那么零碎如何赋值的呢?首先总得找到a这块内存在哪吧?如何找到给a调配的那块内存的呢?当然是通过之前给a变量做的那个标记。通过标记找到这块内存所在的地位,而后间接在开拓好的内存空间存下给a赋值的数据就能够了。
fmt.Println("a的值为", a)
这段代码,咱们暂且先不必去理解fmt.Println是怎么实现的,只用关怀a是怎么取到的,当然是先找到a之前所做的那个标记,找到对应的内存所在的地位,间接往后偏移4个地位把值取出来就行。
这下是不是感觉清晰明了了?
咱们在上述过程中,所说的标记,就是指针.所以指针其实就是一个标记数据所在位置的数据类型而已,只不过他有一些本人非凡的语法而已,而且是一种新的数据类型。这么来看,就很简略了。
指针的定义
指针是一种数据类型,用于示意数据的内存地址。
如何应用指针
咱们来看上面几个例子感受一下
case1
var a string //申明一个字符串类型的变量,初始值为""var b *string //申明一个字符串指针类型的变量,初始值为nil,申明指针类fmt.Println("a:", a, " b:", b)//输入后果为 //a: b: <nil>
留神:
- 申明指针的类型,只须要在后面加上一个*就能够了,这是固定的语法
不论什么指针类型(int, string, *float),初始值都为nil
case2
var name string = "小饭" //申明一个name为string类型,并且赋值为"小饭"var p_name *string = &name //申明一个p_name为*string(字符串的指针类型),并且赋值为&a(在a后面加上一个&的意思是取a的首地址)fmt.Println("name:", name, "name的内存地址", &name, " p_name:", p_name, "p_name的具体值:", *p_name)//输入后果为 //name: 小饭 name的内存地址 0x14000010240 p_name: 0x14000010240 p_name的具体值: 小饭
留神
- 取变量name的首地址,也就是指针的值,须要用&name示意,而取出来的值也只能用指针这种变量类型来保留,所以var p_name *string = &name这段代码是正当的
- p_name的具体值是随机调配的一个16进制的值,0x14000010240,晓得这个代表的是指针的值就行了,因为是随机调配的,所以不同设施是不一样的。
要取一个指针类型指向的具体值,用 (对应的指针类型的变量名)就能间接取到,比方下面的例子,对应的指针类型的变量名为p_name,所以用p_name就能间接取到指针p_name所指向的具体值。
阐明
下面咱们通过&name获取到了name的内存空间的地址是0x14000010240,p_name的变量的值实际上是name变量的内存空间的值,p_name也是一个变量
那么p_name变量所寄存值的中央,是不是也会有一个内存空间呢?是的,p_name这个指针变量也会指向一个内存空间
var name string = "小饭" var p_name *string = &name fmt.Println("name:", name, "p_name的值", p_name, " p_name指针变量的内存地址:", &p_name) //输入 //name: 小饭 p_name的值 0x14000010240 p_name指针变量的内存地址: 0x1400000e028
指针在数组中的利用
大家首先得辨别一个概念,数组指针和指针数组的区别。
数组指针
简略说数组指针就是整个数组都为指针
a, b, c := 1, 2, 3 arr := [3]int{a, b, c} var ptrArr *[3]int ptrArr = &arr arr[1] = 200 //扭转数组的值,并不会影响到对应数组元素的变量自身 fmt.Println(b) fmt.Println(arr[1]) fmt.Println((*ptrArr)[1]) // 能够简略写为:ptrArr[1] //后果输入为 //2 //200 //200
间接扭转数组的某个元素,不会影响到对应元素的变量。
指针数组
简略说就是数组每个元素都为指针
a, b, c := 1, 2, 3 arr := [3]int{a, b, c} arr[1] = 2 // 批改一般数组中的值 // 定义指针数组 var ptrArr [3]*int //每个元素为一个指针 ptrArr = [3]*int{&a, &b, &c} *ptrArr[1] = 200 //批改某个元素的指,不会影响到数组自身 fmt.Println(b) fmt.Println(arr[1]) fmt.Println(*ptrArr[1]) //后果输入 //200 //2 //200
当然指针数组和数组指针有很多细节须要留神,如果这篇文章浏览量还能够,咱们前面专门会开一篇解说这个问题。在这里有个简略的意识即可。心愿大家记得多多转发和点赞哦。
指针在函数中的利用
case1
func main() { var a int = 123 changeData(a) fmt.Println(a)}func changeData(b int) { b = 456}//输入后果//123
大家设想一下最终打印进去的a是123 还是456,当然是123.为什么会这样呢?因为运行到changeData中,把a传进去之后,相当于执行了一步
var b intb = 1
所以天然对b进行任何批改都不会影响到a,输入的天然是123
case2
func main() { var a int = 123 changeData(&a) fmt.Println(a)}func changeData(b *int) { *b = 456}
在这一次函数参数传递中,相当于执行了
var b *intb = &a
b就是指向a的指针,所以*b批改了,a天然也会跟着批改。
golang指针和c语言指针的区别
大家晓得C语言之所以弱小,就是因为c语言反对指针,而且权限特地大,c语言能够对计算机中任何内存的指针进行操作,这样自然而然也会带来一些不平安的因素,所以在golang中,勾销了对指针的一些偏移,翻转等算术运算(+、-、++、--)所以应用起来更平安。
本文由mdnice多平台公布