unsafe 库彷徨在“类型平安”边缘,因为它们绕过了 Golang 的内存平安准则,个别被认为应用该库是不平安的。然而,在许多状况下,unsafe 库的作用又是不可代替的,灵便地应用它们能够实现对内存的间接读写操作。在 reflect 库、syscall 库以及其余许多须要操作内存的开源我的项目中都有对它的援用。
unsafe 库源码极少,只有两个类型的定义和三个办法的申明。
Pointer 类型
这个类型比拟重要,它是实现定位欲读写的内存的根底。官网文档对该类型有四个重要形容:
(1)任何类型的指针都能够被转化为 Pointer
(2)Pointer 能够被转化为任何类型的指针
(3)uintptr 能够被转化为 Pointer
(4)Pointer 能够被转化为 uintptr
举例来说,该类型能够这样应用:
func main() {
i := 100
fmt.Println(i) // 100
p := (*int)unsafe.Pointer(&i)
fmt.Println(*p) // 100
*p = 0
fmt.Println(i) // 0
fmt.Println(*p) // 0
}
Sizeof 函数
该函数的定义如下:
func Offsetof(v ArbitraryType) uintptr
该函数返回由 v 所批示的某构造体中的字段在该构造体中的地位偏移字节数,留神,v 的表达方式必须是“struct.filed”模式。
举例说明,在 64 为零碎中运行以下代码:
type Datas struct{
c0 byte
c1 int
c2 string
c3 int
}
func main(){
var d Datas
fmt.Println(unsafe.Offset(d.c0)) // 0
fmt.Println(unsafe.Offset(d.c1)) // 8
fmt.Println(unsafe.Offset(d.c2)) // 16
fmt.Println(unsafe.Offset(d.c3)) // 32
}
如果晓得的构造体的起始地址和字段的偏移值,就能够间接读写内存:
d.c3 = 13
p := unsafe.Pointer(&d)
offset := unsafe.Offsetof(d.c3)
q := (*int)(unsafe.Pointer(uintptr(p) + offset))
fmt.Println(*q) // 13
*p = 1013
fmt.Println(d.c3) // 1013