Go unsafe 包的使用
unsafe包
golang是一种静态的强类型的语言,所有的类型都是不能随意转换的,Go语言是不允许两个指针类型进行转换的。go官方是不推荐使用unsafe的操作因为它是不安全的,它绕过了golang的内存安全原则,容易使你的程序出现莫名其妙的问题,不利于程序的扩展与维护。但是在很多地方却是很实用。在一些go底层的包中unsafe包被很频繁的使用。
unsafe 定义
package unsafe
//ArbitraryType仅用于文档目的,实际上并不是unsafe包的一部分,它表示任意Go表达式的类型。
type ArbitraryType int
//任意类型的指针,类似于C的*void
type Pointer *ArbitraryType
//确定结构在内存中占用的确切大小
func Sizeof(x ArbitraryType) uintptr
//返回结构体中某个field的偏移量
func Offsetof(x ArbitraryType) uintptr
//返回结构体中某个field的对其值(字节对齐的原因)
func Alignof(x ArbitraryType) uintptr
官方中定义了四个描述:
- 任何类型的指针都可以被转化为Pointer
- Pointer可以被转化为任何类型的指针
- uintptr可以被转化为Pointer
- Pointer可以被转化为uintptr
unsafe的使用
类型转换
使用unsafe可以实现类型的转换,下面的例子可以看到i是一个int类型,使用unsafe.Pointer转换成float64并且还修改了指针对应的值。
func main() {
i := 10
ip := &i
fp := (*float64)(unsafe.Pointer(ip))
*fp = *fp * 3
fmt.Println(i)
}
// 结果: 30
但是使用起来要十分的小心,如果使用不当会引发错误。可以举一个例子:
func main() {
i := 10
ip := &i
fp := (*string)(unsafe.Pointer(ip))
*fp = "a"
fmt.Println(i)
// 结果:19678090
}
上面的误操作就是把int类型转成了string,并且修改了值导致结果出现了错误,并且这种错误
根据位移获取、修改对象的字段
利用unsafe的Pointer和Offsetof函数,可以获取对象的属性,并且可以修改对象的属性
type Student struct {
Name string
Age int
}
func main() {
s := Student{}
s.Name = "Peter"
s.Age = 33
pStudent := unsafe.Pointer(&s)
// 整个对象转换成指针,默认是获取第一个属性
name := (*string)(unsafe.Pointer(pStudent))
fmt.Println("name:", *name)
// 利用Offsetof获取age属性的偏移量获取属性
age := (*int)(unsafe.Pointer(uintptr(pStudent) + unsafe.Offsetof(s.Age)))
fmt.Println("age:", *age)
// 修改指针的值
*name = "Mary"
*age = 20
fmt.Println(s)
}
获取私有变量
可以通过unsafe获取私有变量的值,也可以修改值。这个操作跟上面的获取值是一样的简单的例子如下:
type Teacher struct {
name string
age int
}
func main() {
t := Teacher{"ttt", 20}
pt := unsafe.Pointer(&t)
name := (*string)(unsafe.Pointer(pt))
fmt.Println("name:", *name)
}
根据sizeof函数获取、修改
利用unsafe中的sizeof函数获取数组的值
func main() {
array := []int{0, 1, -2, 3, 4}
pointer := &array[0]
fmt.Print(*pointer, " ")
memoryAddress := uintptr(unsafe.Pointer(pointer)) + unsafe.Sizeof(array[0])
for i := 0; i < len(array)-1; i++ {
pointer = (*int)(unsafe.Pointer(memoryAddress))
fmt.Print(*pointer, " ")
memoryAddress = uintptr(unsafe.Pointer(pointer)) + unsafe.Sizeof(array[0])
}
}
结果:0 1 -2 3 4
大二小的宝
go 语言学习 经验总结记录
202 声望
73 粉丝
推荐阅读
服务器注册发现在Go微服务中的使用
服务注册:将提供某个服务的模块信息(通常是这个服务的IP和端口)注册到1个公共的租价你上去(比如:zookeeper、consul、etcd)
大二小的宝阅读 944
「刷起来」Go必看的进阶面试题详解
逃逸分析是Go语言中的一项重要优化技术,可以帮助程序减少内存分配和垃圾回收的开销,从而提高程序的性能。下面是一道涉及逃逸分析的面试题及其详解。
王中阳Go赞 4阅读 1.9k评论 1
初学后端,如何做好表结构设计?
这篇文章介绍了设计数据库表结构应该考虑的4个方面,还有优雅设计的6个原则,举了一个例子分享了我的设计思路,为了提高性能我们也要从多方面考虑缓存问题。
王中阳Go赞 4阅读 1.7k评论 2
滚蛋吧,正则表达式!
你是不是也有这样的操作,比如你需要使用「电子邮箱正则表达式」,首先想到的就是直接百度上搜索一个,然后采用 CV 大法神奇地接入到你的代码中?
良许赞 4阅读 2.2k
又一款眼前一亮的Linux终端工具!
今天给大家介绍一款最近发现的功能十分强大,颜值非常高的一款终端工具。这个神器我是在其他公众号文章上看到的,但他们都没把它的强大之处介绍明白,所以我自己体验一波后,再向大家分享自己的体验。
良许赞 5阅读 1.8k
一分钟搞明白!快速掌握 Go WebAssembly
最近因为各种奇怪的原因,更多的接触到了 WebAssembly。虽然之前很多博客也翻过写过各种文章,但总感觉欠些味道。于是今天梳理了一版,和大家一起展开学习。
煎鱼赞 4阅读 2.1k
面试官:请说一下如何优化结构体的性能?
使用内存对齐机制优化结构体性能,妙啊!前言之前分享过2篇结构体文章:10秒改struct性能直接提升15%,产品姐姐都夸我好棒 和 Go语言空结构体这3种妙用,你知道吗? 得到了大家的好评。这篇继续分享进阶内容:结...
王中阳Go赞 4阅读 3.7k评论 2
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。