Go语言中的非类型安全指针
介绍:
Golang 语言中的unsafe 包中包含的操作绕过了Golang 程序的类型安全检查,直接操作内存,从而达到提升性能的目的,导入unsafe 包可能是不可移植的,并且不受 Go1 兼容性准则的保护,所以我们应该谨慎使用。
下面主要介绍unsafe 包的 unsafe.Pointer ,它表示任意类型的指针,他类似于C语言中的无类型指针,void* , 可以作为指针类型 * T 和 uintptr 类型值之间相互转换的中转站。
我们知道 Golang 语言中指针类型是 * T ,表示一个指向T类型变量的指针,因为Golang 语言是强类型的静态语言, 为了安全考虑,规定两个不同的指针类型之间不可以相互转换,比如 *int 不能与 * float32 相互转换,但是,实际上是可以使用 unsafe.Pointer 进行转换。
在比如Golang 语言中的内置数据类型,uintptr 也可以表示任何指针,它实际的数值类型,可以用于存储内存地址。它和unsafe.Pointer 最大的区别是 unsafe.Pointer 不支持指针运算,比如 + 运算符 ,但是 uintptr 可以支持。
unsafe.Ponter 类型
有了前面内容的铺垫,我们开始介绍unsafe.Ponter ,它表示指向任意类型的指针,以下是unsafe 的代码。
type ArbitraryType inttype Pointer *ArbitraryType
unsafe.Ponter 类型有四个准换规则:
- 任何类型的指针值*T 都可以转换位unsafe.Pointer
- unsafe.Pointer 可以转换为任何类型的指针值。
- uintptr 可以转换为unsafe.Pointer
- unsafe.Pointer 可以转换为 uintptr。
unsafe.Pointer 允许程序绕过类型安全检查读写任意内存,所以使用适应格外小心。
unsafe.Pointer 包含6个使用模式。
-
使用
unsafe.Pointer
作为中转,将一个指针类型*T
转换为另外一个指针类型*T
。 -
将
unsafe.Pointer
转换为 uintptr(但不返回给unsafe.Pointer
),然后使用 uintptr 值。 -
将
unsafe.Pointer
转换为 uintptr,然后使用 uintptr 值进行算术运算,最后将运算结果 uintptr 值再转换为unsafe.Pointer
-
调用
syscall.Syscall
时,将unsafe.Pointer
转换为 uintptr 值,作为参数传递。 -
将
reflect.Value.Pointer
或reflect.Value.UnsafeAddr
的返回结果 uintptr 值,从 uintptr 转换为unsafe.Pointer
。 -
将
reflect.SliceHeader
或reflect.StringHeader
值的 Data 字段与unsafe.Pointer
进行转换。