Go教程:16-什么时候使用指针Pointer
1. Pointer指针
指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址.
在计算机科学中,指针(Pointer)是编程语言中的一个对象, 利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值. 由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元.因此,将地址形象化的称为“指针”.意思是通过它能找到以它为地址的内存单元.
1.1 C/C++中复杂的指针
int (*func)(int *p, int (*f)(int*))
因为C语言所有复杂的指针声明,都是由各种声明嵌套构成的.
如何解读复杂指针声明呢?右左法则是一个既著名又常用的方法.
不过,右左法则其实并不是C标准里面的内容,它是从C标准的声明规定中归纳出来的方法.C标准的声明规则,是用来解决如何创建声明的,而右左法则是用来解决如何辩识一个声明的,两者可以说是相反的.
1.2 Go语言指针
Go语言保留着C中值和指针的区别,但是对于指针繁琐用法进行了大量的简化,引入引用的概念. 所以在Go语言中,您几乎不用担心会因为直接操作内寸而引起各式各样的错误.
3. Go语言指针
每一个变量都会分配一块内存,数据保存在内存中,内存有一个地址,就像门牌号,通过这个地址就可以找到里面存储的数据. 指针就是保存这个内存地址的变量.
3.1 &
取得变量的地址
//为了说明类型,我采用了显性的变量定义方法,实际开发中更多的是用“:=”自动获取类型变量类型
var mystr string = "Hello!"
var mystrP *string = &mystr
fmt.Println(mystrP)
3.2 *
取得指针变量指向的内存地址的值
在之前的代码的后面增加一句代码:fmt.Println(*mystrPointer)
3.3 nil
代表空指针
指针表示指向内存的地址,如果对为nil的指针进行解引用的话就会导致panic.
var p *int
p == nil // true
*p // panic: invalid memory address or nil pointer dereference
4. 什么时候使用指针
在Go语言中,默认是按值传递.当一个变量当作参数传递的时候,会创建一个变量的副本, 然后传递给函数或者方法,您可以看到这个副本的地址和变量的地址是不一样的. 当变量当做指针被传递的时候,一个新的指针被创建,它指向变量同样的内存地址, 所以您可以将这个指针看成原始变量指针的副本.
4.1 func Func(t *Type) {}
VS func Func(t Type) {}
入参是指针,参数值可以在函数内部被修改.
4.2 func Func()(t *Type) {}
VS func Func()(t Type) {}
返回值类型不同之处在于取值的方式,指针类型需要使用 * 号读取数据.
其次返回值指针判断空值更加容易简洁,t != nil
.
4.3 func (t *Type) Method() {}
VS func (t Type) Method() {}
如果要在方法中更改receiver的状态,操纵receiver的值,请使用指针receiver. 使用值receiver是不可能的, 它按值复制.对值receiver的任何修改都是该值receiver副本的本地修改.
值receiver在原始类型值的副本上运行. 这意味着涉及成本,特别是如果结构非常大,并且接收的指针更有效. 如果您不需要编辑receiver值,请使用值receiver.
值receiver是并发安全的,而指针receiver不是并发安全的.
有一种情况,您可能希望将指针receiver用于通常使用值receiver的方法, 并且当您在该类型上定义了其他指针receiver时,为了保持一致性, 您应该在所有方法中使用指针receiver.