golang unsafe实践与原理

指针类型

关于指针的好处这里就不描述了。golang是一种强类型的语言,golang 的指针多了一些限制。但这也算是 Go 的成功之处:既可以享受指针带来的便利,又避免了指针的危险性。下面主要讲一下golang里面对指针的一些限制:

  1. 指针是不能做数学运算。

我们在其余的语言(C++等),我们如果想通过数组指针访问不同的索引的元素,直接怼 ptr++ 之类的操作就可以。但是在golang里面对指针的任何数学运算都是不允许的。

  1. 不同类型的指针不能相互转换。

也就是说一个指针只能指向一种数据类型,即使是golang里面的组合关系,或者是同样是想某个interface的两个struct也不能互相转换。golang的指针很纯粹。

  1. 不同类型的指针不能使用 == 或者 != 比较。

  2. 不同类型的指针变量不能相互赋值

unsafe

golang里面的指针是类型安全的,是因为编译器帮我们做了很多的检查工作,这必然会带来性能的损失。 对于高阶程序员有非类型安全的指针,这就是 unsafe 包提供的 unsafe.Pointer。在某些情况下,它会使代码更高效,当然,也更危险。

Pointer 表示指向任意类型的指针。有四种特殊操作可以用于指针类型而不能用于其他类型:

  • 任意类型的指针值可以转换为 Pointer
  • Pointer 均可转换为任意类型的指针值
  • uintptr 均可以转换为 Pointer
  • Pointer 均可以转换为 uintptr

uintptr:uintptr 是 Go 的内置类型。返回无符号整数,可存储一个完整的地址,后续常用于指针数学运算。

Pointer 允许程序破坏类型系统并对任意的内存进行读写。使用应非常小心。

unsafe 包用于 Go 编译器,在编译阶段使用。从名字就可以看出来,它是不安全的,官方并不建议使用。

但是高阶的 Gopher,怎么能不会使用 unsafe 包呢?它可以绕过 Go 语言的类型系统,直接操作内存。例如,一般我们不能操作一个结构体的未导出成员,但是通过 unsafe 包就能做到。unsafe 包让我可以直接读写内存,还管你什么导出还是未导出。

为什么有 unsafe

Go 语言类型系统是为了安全和效率设计的,有时,安全会导致效率低下。有了 unsafe 包,高阶的程序员就可以利用它绕过类型系统的低效。因此,它就有了存在的意义,阅读 Go 源码,会发现runtime里面有大量使用 unsafe 包的例子。

unsafe实现原理

先看源码里面 unsafe.Pointer 的定义:

type ArbitraryType int
type Pointer *ArbitraryType

从命名来看,Arbitrary 是任意的意思,也就是说 Pointer 可以指向任意类型,实际上它类似于 C 语言里的 void*

unsafe 包还有其他三个函数:

func Sizeof(x ArbitraryType) uintptr
func Offsetof(x ArbitraryType) uintptr
func Alignof(x ArbitraryType) uintptr

Sizeof 返回类型 x 所占据的字节数,但不包含 x 所指向的内容的大小。例如,对于一个指针,函数返回的大小为 8 字节(64位机上),一个 slice 的大小则为 slice header 的大小。

Offsetof 返回结构体成员在内存中的位置离结构体起始处的字节数,所传参数必须是结构体的成员。

Alignof 返回 m,m 是指当类型进行内存对齐时,它分配到的内存地址能整除 m。

注意到以上三个函数返回的结果都是 uintptr 类型,这和 unsafe.Pointer 可以相互转换。三个函数都是在编译期间执行,它们的结果可以直接赋给 const 型变量。另外,因为三个函数执行的结果和操作系统、编译器相关,所以是不可移植的。

综上所述,unsafe 包提供了 2 点重要的能力:

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

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


                
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值