6 unsafe
对于一个结构体,通过offset函数可以获取结构体成员的偏移量,进而获取成员的地址,读写该地址的内存,就可以改变成员值的目的。
这里有一个内存分配相关的事实:结构体会被分配一块连续的内存,结构体的地址也代表了第一个成员的地址。
unsafe 包是 Go 语言里一个“不讲武德”的工具,它允许程序绕过 Go 的类型安全机制,直接操作内存,就像 C/C++ 里的指针一样。虽然名字叫 unsafe,但只要用得对,它能帮我们干一些常规手段干不了的事。
修改私有成员:在 Go 中,结构体的小写字段是包外不可见的,但通过 unsafe 包可以计算出字段的内存偏移量,然后直接用指针修改它,相当于“走后门”改了别人家的私房钱。这常用于测试代码中,但生产环境慎用。
获取 slice 和 map 的长度:slice 和 map 的内部结构其实是一个结构体(slice 包含 array、len、cap;map 包含 count 等字段),通过 unsafe 可以把它们强制转换成对应的内部表示,直接读取长度字段,比调用 len() 还快。但 map 的读取需要小心并发,因为 map 的内部结构在运行时可能会变。
字符串和 byte 切片的零复制转换:这是 unsafe 最经典的用法。string 和 []byte 底层都是指向数组的指针加长度,但 Go 不允许直接转换(因为 string 是不可变的,而 []byte 是可变的)。通过 unsafe 可以让它们共用同一块底层内存,转换时不复制数据,性能极高。这在处理大字符串或高频转换的场景下特别有用,但千万注意:转换后如果修改了 []byte,string 也会跟着变,破坏了 string 的不可变性,容易出 bug。
总结一句话:unsafe 是 Go 留给你的“后门”,能让你突破类型限制直接操作内存,性能极高,但也极易踩坑,非必要不用,用了一定要小心。

浙公网安备 33010602011771号