2021再谈Go指针

119 阅读2分钟

1. 概念

我们看看go是怎么定义指针的:

image-20210922212614829

大意是:指针类型表示指向给定类型变量的所有指针集,称为指针的基类型。未初始化指针的值为零。

官方这段解释,说了等于没说。指针到底是什么,今天来搞明白他。实话是说,刚开始了解到指针的时候,内心是恐惧的,有一部分原因是很多人把指针给神话了。

下面我们来举一个例子,让大家理解指针。

1、 同其他类型一样,指针也是一个类型。

string 是一个类型,int是一个类型,pointer也是一个类型。

2、string支持的运算有:+, int支持的运算有+ - * /

指针支持的运算有:* 取值

3、*string *int *byte 都是指针一种类型,类似于[]int 表示一个int数组,[]string 表示一个string数组。 另外,这里的* 和上面的取值是不同的涵义,这里是表示类型定义,而上面2中表示的操作符号。

我们来举一个例子吧:

image-20210922215301526

风筝的把手为啥可以控制风筝?因为把手通过一根线连在了风筝上面。同理,指针变量为啥可以控制普通变量,因为他里面存的是普通变量的地址。通过这个地址,可以对地址上面的值做修改。

image-20210922223509975

2. 基本操作

go语言中,如果不通过unsafe包,则对于指针的操作相对简单,请看下举例和注释

 ​
 func main() {
     //
     var AA string
     AA = "风筝"
     //把手
     var BB *string
 ​
     //用一跟线,将风筝链接到把手上; &取地址,
     BB = &AA
     //打印BB的值,也就是AA的地址
     fmt.Println("BB= ", BB)
     //通过BB中存的值(AA的地址取值),也就是通过AA的地址取AA的值
     fmt.Println("*BB= ", *BB)
 ​
     //验证一下 AA的地址是不是 = BB的值
     fmt.Println("&AA= ", &AA)
 ​
 }
 ​
 //BB=  0xc000040240
 //*BB=  风筝
 //&AA=  0xc000040240
 ​

3. unsafe高级用法及转换

通过指针的加减运算,对地址所在的值做修改。

 ​
 func main() {
 ​
     var pv = new(v)
 ​
     var i = (*int32)(unsafe.Pointer(pv))
     *i = 100
     fmt.Println("pv.i: ", pv.i)
     
     //
     var j = (*int64)(unsafe.Pointer(uintptr(unsafe.Pointer(pv)) + 4))
 ​
     *j = 123
 ​
     fmt.Println("pv.j: ", pv.j)
 }
 ​

unsafe.Pointer(uintptr(unsafe.Pointer(pv)) 获取到结构体的初始位置,也就是第一个元素的位置。

+ 4表示加四个字节的位置,就会偏移到j的地址。

unsafe.Pointer: 表示通用指针类型,任何指针类型都可以转换为unsafe.Pointer

uintptr: 表示一个指针地址,通过unsafe.Pointer转换而来,可以进行加减运算

image-20210922222619365

今天就先到这里吧,后面有时间聊聊逃逸分析吧

\