Go语言学习12-反射和Unsafe

reflect.TypeOf vs. reflect.ValueOf

  • reflect.TypeOf 返回类型 (reflect.Type)
  • reflect.ValueOf 返回类型 (reflect.Value)
  • 可以从 reflect.Value 获得类型
  • 通过 kind 来判断类型

判断类型——Kind()

1
2
3
4
5
6
7
8
9
10
11
func CheckType(v interface{}) {
t := reflect.TypeOf(v)
switch t.Kind() {
case reflect.Float32, reflect.Float64:
fmt.Println("Float")
case reflect.Int, reflect.Int32, reflect.Int64:
fmt.Println("Integer")
default:
fmt.Println("Unknown", t)
}
}

利用反射编写灵活的代码

按名字访问结构的成员

1
reflect.ValueOf(*e).FieldByName("Name")

按名字访问结构的方法

1
reflect.ValueOf(e).MethodByName("UpdateAge").Call([]reflect.Value{reflect.ValueOf(1)})

Struct Tag

1
2
3
4
type BasicInfo struct {
Name string `json:"name"`
Age int `json:"age"`
}

访问 StructTag

1
2
3
4
5
if nameField, ok := reflect.TypeOf(*e).FieldByName("Name"); !ok {
t.Error("Failed to get 'Name' field.")
} else {
t.Log("Tag:format", nameField.Tag.Get("format"))
}

Reflect.Type 和 Reflect.Value 都有 FieldByName ⽅方法,注意他们的区别

万能程序

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
func FillBySettings(st interface{}, settings map[string]interface{}) error {
// func(v value) Elem() Value
// elem returns the value that the interface v contains or that the pointer v points to.
// It panics if v's Kind is not Interface or Ptr
// It returns the zero Value if v is nil.

if reflect.TypeOf(st).Kind() != reflect.Ptr {
// Elem() 获取指针指向的值
if reflect.TypeOf(st).Elem().Kind() != reflect.Struct {
return errors.New("the first param should be a pointer to the struct type")
}
}

if settings == nil {
return errors.New("settings is nil")
}
var (
field reflect.StructField
ok bool
)

for k, v := range settings {
if field, ok = (reflect.ValueOf(st)).Elem().Type().FieldByName(k); !ok {
continue
}
if field.Type == reflect.TypeOf(v) {
vstr := reflect.ValueOf(st)
vstr = vstr.Elem()
vstr.FieldByName(k).Set(reflect.ValueOf(v))
}
}
return nil
}

反射的特点

  • 提高了程序的灵活性
  • 降低了程序的可读性
  • 降低了程序的性能

“不安全” 编程

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
func TestUnsafe(t *testing.T) {
i := 10
f := *(*float64)(unsafe.Pointer(&i))
t.Log(unsafe.Pointer(&i))
t.Log(f)
}

// The cases is suitable for unsafe
type MyInt int

// 合理的类型转换
func TestConvert(t *testing.T) {
a := []int{1, 2, 3, 4, 5}
b := *(*[]MyInt)(unsafe.Pointer(&a))
t.Log(b)
}

// 原子类型操作
func TestAtomic(t *testing.T) {
var shareBufPtr unsafe.Pointer
writeDataFn := func() {
data := []int{}
for i := 0; i < 100; i++ {
data = append(data, i)
}
atomic.StorePointer(&shareBufPtr, unsafe.Pointer(&data))
}
readDataFn := func() {
data := atomic.LoadPointer(&shareBufPtr)
fmt.Println(data, *(*[]int)(data))
}
var wg sync.WaitGroup
writeDataFn()
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
for i := 0; i < 10; i++ {
writeDataFn()
time.Sleep(time.Microsecond * 100)
}
wg.Done()
}()
wg.Add(1)
go func() {
for i := 0; i < 10; i++ {
readDataFn()
time.Sleep(time.Microsecond * 100)
}
wg.Done()
}()
}
wg.Wait()
}