指针类型

  1. Go的指针不能进行数学运算
  2. 不同类型的指针不能相互转换
  3. 不同类型的指针不能使用 == 或 != 比较
  4. 不同类型的指针变量不能相互赋值

unsafe是什么

unsafe是非类型安全的指针。让代码变得更高效,也变得更危险。
绕过go语言的类型检查,直接操作内存。

为什么存在

go语言为了安全和效率,但是普通的语法安全但是效率低,而通过unsafe包直接操作内存达到高效的效果。

实现原理

  1. type Pointer *ArbitraryType
  2. // Sizeof 返回类型 x 所占据的字节数,但不包含 x 所指向的内容的大小。
  3. // 例如,对于一个指针,函数返回的大小为 8 字节(64位机上),
  4. // 一个 slice 的大小则为 slice header 的大小。
  5. func Sizeof(x ArbitraryType) uintptr //
  6. //Offsetof 返回结构体成员在内存中的位置离结构体起始处的字节数,所传参数必须是结构体的成员。
  7. func Offsetof(x ArbitraryType) uintptr
  8. //Alignof 返回 m,m 是指当类型进行内存对齐时,它分配到的内存地址能整除 m。
  9. func Alignof(x ArbitraryType) uintptr

unsafe包的特性:

  1. 任何类型的指针和 unsafe.Pointer 可以相互转换。
  2. uintptr 类型和 unsafe.Pointer 可以相互转换。

pointer 不能直接进行数学运算,但可以把它转换成 uintptr,对 uintptr 类型进行数学运算,再转换成 pointer 类型。

通过unsafe包可以获取 slice 长度和容量以及map的长度。
通过Offsetof获取结构体的成员重新更改结构体私有成员变量值等
string 和 slice 也可以相互转换-通过src/reflect/values.go中的结构体进行转换

总结

go unsafe包绕过go语言的类型检查。直接操作go的内存。存在一定风险。但是某些场景提高了代码效率。

通过 Sizeof、Offsetof、Alignof 三个函数可以获取变量的大小、偏移、对齐等信息。
uintptr 可以和 unsafe.Pointer 进行相互转换,uintptr 可以进行数学运算。这样,通过 uintptr 和 unsafe.Pointer 的结合就解决了 Go 指针不能进行数学运算的限制。
通过 unsafe 相关函数,可以获取结构体私有成员的地址,进而对其做进一步的读写操作,突破 Go 的类型安全限制