golang unsafe package

使用unsafe.Pointer来取切片的属性

func testPointer() {
	s := make([]int, 9, 20)
	s = append(s, 2)
	len := *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + uintptr(8)))
	cap := *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + uintptr(16)))

	dataPointer := *(*int)(unsafe.Pointer(&s))
	data1 := *(*int)(unsafe.Pointer(uintptr(dataPointer)))

	fmt.Printf("len: %d cap:%d \n", len, cap)
	fmt.Printf("dataPointer: %d  data1:%d \n", dataPointer, data1)

	i := 0
	for {
		if i >= len {
			break
		}
		fmt.Printf("data%d:%d \n", i, *(*int)(unsafe.Pointer(uintptr(dataPointer) + uintptr(8*i))))
		i++
	}
}

unsafe 包绕过了 Go 的类型系统,达到直接操作内存的目的,使用它有一定的风险性。但是在某些场景下,使用 unsafe 包提供的函数会提升代码的效率,Go 源码中也是大量使用 unsafe 包。

unsafe 包定义了 Pointer 和三个函数:

通过三个函数可以获取变量的大小(Sizeof)、偏移(Offsetof)、对齐(Alignof)等信息。

uintptr 可以和 unsafe.Pointer 进行相互转换,uintptr 可以进行数学运算。这样,通过 uintptr 和 unsafe.Pointer 的结合就解决了 Go 指针不能进行数学运算的限制。

通过 unsafe 相关函数,可以获取结构体私有成员的地址,进而对其做进一步的读写操作,突破 Go 的类型安全限制。