在我们这么久的go基础之旅中一直忽略一个问题--指针。为什么一直不跟大家聊指针这个事情呢?原因有二:其一,一开始料指针大家感觉啥?这还用聊。其二,刚接触go根部体会不到指针这有什么用处……
指针这个概念在很多的高级语言中被刻意的规避掉,比如Python PHP Java(大部分Java的类型默认其实就是引用类型),这是因为很多时候大家容易忽略指针,或者说指针太过于抽象容易让一大部分人望而却步。不过今天我们就是来聊golang中的指针问题,所以大家完全可以抱着平和心态来看指针的问题。
好了,今天的目的就是为了说说lz最近过程中遇到的,或者说是忽略的指针问题吧(大家共勉哈)。
1 对只声明的变量进行指针操作
var a Person
上文中的a,假如直接使用在后续中采用指针操作赋值会出现pain,因为内存中并没给a分配空间
2 对数组的指针操作
list:=[]Person{}for _, value:=range list{value.Name = "xxx"}
我们来分析一下,上面的数组遍历赋值问题:
1 list是个存储的值类型
2 range遍历过程中 value是一个临时变量会被循环使用
3 对value的操作是对一个临时变量进行的赋值,并不能对list中的变量造成影响
4 修改建议:将list存储类型修改为指针类型 list:=[]*Person{}
3 函数参数
我们知道函数的参数是个临时变量,随着函数的出栈而结束生命周期,而我们经常会错误的通过函数声明值类型而去试图修改原有的值类型数据
func a( a1 Person){ a1.Name = "a1"}
func aa(a1 *Person){ a1.Name = "aa1"}//调用b:=Person{Name:"YuLong"}a(b)aa(&b)
上面中我们的a 和 aa两个函数,哪个能够修改b的类型呢?大家是否使用过a这种来视图修改原有
我们实况中的操作的是内存中复制出的分身而虚框中操作的地址根据地址直接执行内存单元操作
4 接口的实现
go中的接口不能进行匿名实例化,当然这个也没什么好纠结的,想在的高级语言中有能进行实例化的(Java),不能进行实例化的(swift),可谓是个有千秋。但是go的接口实现却不相同(鸭子模型)可以认为是特殊的函数吧
而go中方法实现分为指针方法和值方法(可能是造词吧)因此接口的实现也就出现了两种方式:值 和 指针对应的。那么有何不同呢?今天我们简短的先科普一下,后续出一篇幅介绍具体的底层理论
与上面的3 情况类似
1 值实现接口
对于值实现的接口,在调用的时候,其实是在内存中复制出一个分身赋值给接口然后再去走对应的方法(这就是为啥值实现的接口无法更改自身属性)
2 指针实现接口
对于指针类型实现的接口时,转义为接口类型数据进行调用时其实是将原有类型的指针赋值给接口类型,那么无论接口指向还是源数据类型的操作都是同一片数据内存空间,那么接口操作管理的空间数据更改也就是源指针类型的空间啦