目录

Go Unsafe 使用

修改私有成员

 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
package main

import (
	"container/list"
	"fmt"
	"reflect"
	"unsafe"
)

func main() {
	l := list.New()
	l.PushFront("foo")
	l.PushFront("bar")

	// Get a reflect.Value fv for the unexported field len.
	fv := reflect.ValueOf(l).Elem().FieldByName("len")
	fmt.Println(fv.Int()) // 2

	// Try to set the value of len.

	// With Set
	//fv.Set(reflect.ValueOf(3)) // ILLEGAL
	//fmt.Println(l.Len())

	ll := (*int)(unsafe.Pointer(fv.UnsafeAddr()))
	*ll = 20

	fmt.Println(l.Len())
}

使用 unsafe 获取未导出成员, 调用其方法

 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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package main

import (
	"fmt"
	"reflect"
	"unsafe"
)

type MyConn struct {
	name string
	c    *Conn
}

func (c *MyConn) GetName() string {
	return c.GetName()
}

type Conn struct {
	name string
}

func (c *Conn) GetName() string {
	return c.name
}

func (c *Conn) Println() {
	fmt.Println(c.name)
}

func main() {
	myConn := &MyConn{
		name: "myConn's name",
		c: &Conn{
			name: "1",
		},
	}

	fmt.Println(myConn.c.GetName()) // Output: 1

	fmt.Println(myConn.name)        // Output: myConn's name
	namePtr := (*string)(unsafe.Pointer(uintptr(unsafe.Pointer(myConn)) + unsafe.Offsetof(myConn.name)))
	*namePtr = "99"
	fmt.Println(myConn.name)        // Output: 99

	nameRvPtr :=reflect.ValueOf(myConn).Elem().FieldByName("name")
	namePtr2 := (*string)(unsafe.Pointer(nameRvPtr.UnsafeAddr()))
	*namePtr2 = "100"
	fmt.Println(myConn.name)        // Output: 100

	myConn.c.name = "c's name method-1"
	connrv := reflect.ValueOf(myConn).Elem().FieldByName("c").Elem()
	conn := (*Conn)(unsafe.Pointer(connrv.UnsafeAddr()))
	conn.Println()                  // c's name method-1

	myConn.c.name = "c's name method-2"
	conn2 := (*Conn)(unsafe.Pointer(uintptr(unsafe.Pointer(myConn)) + unsafe.Offsetof(myConn.c)))
	conn2.Println()                 // ???
}