- unsafe 包提供了 2 点重要的能力:
- 任何类型的指针和 unsafe.Pointer 可以相互转换。uintptr 类型和 unsafe.Pointer 可以相互转换。
pointer 不能直接进行数学运算,但可以把它转换成 uintptr,对 uintptr 类型进行数学运算,再转换成 pointer 类型。
func main() {
p := Programmer{"stefno", 18, "go"}
fmt.Println(p)
lang := (*string)(unsafe.Pointer(uintptr(unsafe.Pointer(&p)) + unsafe.Sizeof(int(0)) + unsafe.Sizeof(string(""))))
*lang = "Golang"
fmt.Println(p)
}
// uintptr 是一个整数类型,它足够大,可以存储
type uintptr uintptr
如下,map从汇编上可以知道是*hmap
类型的,但是语言层面可见的就是map结构。Pointer可以转化的必要条件是语言(语法检查工具)可见范围内要出现取引用符&
package main
import (
"fmt"
"unsafe"
)
type myInt int
type myIntPtr *int
func main() {
mp := make(map[string]int)
mp["qcrao"] = 100
mp["stefno"] = 18
count := *(**int)(unsafe.Pointer(&mp))
fmt.Println(count, len(mp)) // 2 2
var fooi myInt = 1
var i int = 5
var fooip myIntPtr = &i
fmt.Println(unsafe.Pointer(fooip))
fmt.Println(unsafe.Pointer(&fooi))
}
还有一点要注意的是,uintptr 并没有指针的语义,意思就是 uintptr 所指向的对象会被 gc 无情地回收。而 unsafe.Pointer 有指针语义,可以保护它所指向的对象在“有用”的时候不会被垃圾回收。