Go语言中的unsafe包非常简单,但是威力强大,用不少就出问题。整个包就这些代码:
1
2
3
4
5
6
7
|
package unsafe
type ArbitraryType int
type Pointer *ArbitraryType
func Sizeof(x ArbitraryType) uintptr
func Offsetof(x ArbitraryType) uintptr
func Alignof(x ArbitraryType) uintptr
|
一个指针就能让你在内存的海洋随意穿梭,没有限制,你走到哪里看到哪里,想从什么角度看就给你呈现什么角度的值。这让我想起了《黑客帝国》中的巡游机器人…
示例
下面这个例子,加深对数据类型,和unsafe.Pointer的认识。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
type (
dataType struct{}
emptyInterface struct {
typ *dataType
ptr unsafe.Pointer
}
)
func UnsafeAddr() {
var num = int32(10)
pNum := &num
ptr := unsafe.Pointer(pNum)
println(num)
println(ptr)
println(uintptr(ptr))
*(*int32)(ptr) = 11
println(num)
println("++++++++++++++++++")
var inter interface{}
inter = pNum
println(inter)
println("++++++++++++++++++")
pp := (*emptyInterface)(unsafe.Pointer(&inter))
println(pp.typ)
println(pp.ptr)
}
|
结果如下:
10
0xc00009bf0c
824634359564
11
++++++++++++++++++
(0x76cc60,0xc00009bf0c)
++++++++++++++++++
0x76cc60
0xc00009bf0c
下面是调试时,变量值情况:
string不可改写
看下面的实验,我们试图修改字符串中某个字符,不管是正常访问,还是通过黑魔法将字符串转换成byte切片再访问,结果都一样,抛异常,不让修改。但底层数据存储是byte切片的时候,都是能改的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
func BTS(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
func STB(s string) (b []byte) {
sh := *(*reflect.StringHeader)(unsafe.Pointer(&s))
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len
return b
}
var bytSrc = []byte("bbbbbb")
var strSrc = "aaaaaa"
func StringBytesTrans() {
// 底层是字符串,可读取,修改抛异常
//var list = strSrc
var list = STB(strSrc)
// 底层是byte切片,读取或修改,都可以
//var list = bytSrc
//var list = BTS(bytSrc)
usp := unsafe.Pointer(&list)
fmt.Println(*(*int)(unsafe.Pointer(uintptr(usp) + 8)))
add := (*byte)(unsafe.Pointer(*(*uintptr)(usp) + 1))
fmt.Println(*add)
*add = 109
fmt.Printf("%s", list)
}
|
结果如下:
6
98
bmbbbb # 此处的打印,如果底层是字符串存储的,都会抛异常
(完)