Go官方包提供了一个unsafe
包,在这个包里面有含够绕开Go程序类型安全的操作。 既然是unsafe
包,使用起来一定要特别小心。尽管unsafe
有点危险,但是它也难以置信的有用。
unsafe
的操作:
- A pointer value of any type can be converted to a Pointer.
- A Pointer can be converted to a pointer value of any type.
- A uintptr can be converted to a Pointer.
- A Pointer can be converted to a uintptr.
注意区别一般类型指针与unsafe
指针。unsafe.Pointer
类型指针能够覆盖Go类型系统。一个uintptr
能够被转化为一个unsafe.Pointer
类型,反之也一样。任何类型的指针能够转化为一个unsafe.Pointer
指针。
运算
简单转化操作:
// unsafe.Pointer to a pointer to an integer.
(* int)(unsafePtr)
// Pointer to an integer to an unsafe.Pointer
unsafe.Pointer(intPtr)
// unsafe.Pointer to a uintptr
uintptr(unsafePtr)
// uintptr to unsafe.Pointer
unsafe.Pointer(unsignedIntVar)
// uintptr to a pointer to an integer
(* int)(unsafe.Pointer(unsignedIntVar))
// pointer to an integer to a uintptr
uintptr(unsafe.Pointer(intPtr))
下面的实例就是一个运算操作 –指针偏移。
intArray := [...]int{10, 20}
fmt.Printf("\nintArray: %v\n", intArray)
intPtr := &intArray[0]
fmt.Printf("\nintPtr=%p, *intPtr=%d.\n", intPtr, *intPtr)
nextIntPtr := uintptr(unsafe.Pointer(intPtr)) + unsafe.Sizeof(intArray[0])
intPtr = (*int)(unsafe.Pointer(nextIntPtr))
fmt.Printf("\nintPtr=%p, *intPtr=%d.\n\n", intPtr, *intPtr)
上面代码中,我们展示了unsafe.Pointer
可以转化为任意类型的指针。
nextIntPtr := uintptr(unsafe.Pointer(intPtr)) + unsafe.Sizeof(intArray[0])
上面代码,uintptr的变量nextIntPtr定义为intPtr指针点下移一个数组元素空间大小unsafe.Sizeof(intArray[0])
。即当前元素的地址位置下移到下一个元素位置上。
类型转化
下面例子说明了如何利用将unsafe.Pointer
不同的变量指向同一个地址。
type MyStr string
a := []MyStr{"10", "100", "1000"}
// b := ([]MyStr)(a) // error: cannot convert a (type []MyStr) to type []MyStr
b := *(*[]MyStr)(unsafe.Pointer(&a))
b[0]= "0"
fmt.Println("a =", a) // a = [0 100 1000]
fmt.Println("b =", b) // b = [0 100 1000]
a[2] = "CONVERT"
fmt.Println("a =", a) // a = [0 100 CONVERT]
fmt.Println("b =", b) // b = [0 100 CONVERT]
总结
unsafe
包服务于Go编译器而不是Go运行环境。- 使用unsafe命名这个包名,说明使用这个包的时候需要特别小心。
unsafe.Pointer
不总是一个糟糕的主意,有时候,我们必须使用它。- unsafe包可能会被误用,其结果导致危险的境地。
欢迎加入我的微信公众号
版权声明:本文为GreatElite原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。