Eli's Blog

1. 反射

反射:在运行时,动态获取对象的类型信息和内存结构

反射操作所需要的全部信息都源自接口变量,接口变量除了存储自身类型外,还会保存实际对象的类型数据

将任何传入的对象转换为接口类型:

1
2
func TypeOf(o interface{}) Type
func ValueOf(o interface{}) Value

2. 类型(Type)

reflect.TypeOf() 返回对象类型

1
2
3
4
func TypeOf(i interface{}) Type {
eface := *(*emptyInterface)(unsafe.Pointer(&i))
return toType(eface.typ)
}

2.1 Type和Kind的区别

  • Type: 真实类型(静态类型) t.Name()
  • Kind: 基础类型(底层类型) t.Kind()
1
2
3
4
5
6
7
8
func main() {
type X int

var a X = 100
t := reflect.TypeOf(a)

fmt.Println(t, t.Name(), t.Kind()) // main.X X int
}

2.2 基类型和指针类型

1
2
3
4
5
6
7
8
9
10
func main() {
x := 20

tx := reflect.TypeOf(x)
tp := reflect.TypeOf(&x)

fmt.Println(tx, tx.Name(), tx.Kind()) // int int int
fmt.Println(tp, tp.Name(), tp.Kind()) // *int ptr
fmt.Println(tx == tp.Elem()) // true
}

2.3 方法Type.Elem()

返回引用类型 (指针、数组、切片、字典(值)或 通道) 的基类型

1
2
3
4
5
6
7
8
9
10
11
12
13
func main() {
a := [...]byte{1, 2, 3}
s := make([]string, 5)
m := make(map[int]string)

ta := reflect.TypeOf(a)
ts := reflect.TypeOf(s)
tm := reflect.TypeOf(m)

fmt.Println(ta, ta.Elem()) // [3]uint8 uint8
fmt.Println(ts, ts.Elem()) // []string string
fmt.Println(tm, tm.Elem()) // ma[[iny]string string
}

2.4 辅助判断方法

Implements(), ConvertibleTo(), AssignableTo()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
func main() {
type X int
var a X

t := reflect.TypeOf(a)
fmt.Println(t) // main.X

ts := reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
fmt.Println(ts) // fmt.Stringer

ti := reflect.TypeOf(10)
fmt.Println(ti) // int

fmt.Println(t.Implements(ts)) // false
//fmt.Println(t.Implements(ti)) // panic: non-interface type passed to Type.Implements

fmt.Println(t.ConvertibleTo(ts)) // false
fmt.Println(t.ConvertibleTo(ti)) // true

fmt.Println(t.AssignableTo(ts)) // false
fmt.Println(t.AssignableTo(ti)) // false
}

2.5 结构体 反射类型

Field(), FieldByIndex(), FieldByName(), FieldByNameFunc() 获取 StructField结构体中的内容

1
2
3
4
5
6
7
8
9
10
type StructField struct {
Name string
PkgPath string

Type Type // field type
Tag StructTag // field tag string
Offset uintptr // offset within struct, in bytes
Index []int // index sequence for Type.FieldByIndex
Anonymous bool // is an embedded field
}
1
2
3
4
5
6
7
8
9
10
11
12
13
func main() {
user := User{"Jack", 12}

t := reflect.TypeOf(user)
for i := 0; i < t.NumField(); i++ {
tf := t.Field(i)
fmt.Printf("%s: %s %v\n", tf.Name, tf.Type, tf.Tag)
}

if tf, ok := t.FieldByName("Age"); ok {
fmt.Printf("%s: %s\n", tf.Name, tf.Tag.Get("json"))
}
}

3. 值(Value)

接口变量会复制对象,是unaddressable的。要想修改目标对象,必须使用指针

1
2
3
4
5
6
7
8
9
10
func main() {
a := 5

va := reflect.ValueOf(a)
vp := reflect.ValueOf(&a).Elem()
fmt.Println(va, vp) // 5 5

fmt.Println(va.CanAddr(), va.CanSet()) //false false
fmt.Println(vp.CanAddr(), vp.CanSet()) // true true
}

3.1 结构体反射

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
type User struct {
Id int
Name string
Age byte
}

func (u User) Hello() {
fmt.Println("Hello", u.Name)
}

func (u User) Say(msg string) {
fmt.Println(u.Name, "say", msg)
}

func main() {
u := User{1, "Jack", 23}

Info(u)
Set(&u)
fmt.Println(u)
}

func Info(o interface{}) {
t := reflect.TypeOf(o)
fmt.Println("Type:", t) // Type: main.User

// pointer-interface,直接返回
if k := t.Kind(); k != reflect.Struct {
fmt.Println("A Pointer Interface")
return
}

v := reflect.ValueOf(o)

fmt.Println("Fields:")
for i := 0; i < v.NumField(); i++ {
field := t.Field(i)
value := v.Field(i).Interface()
fmt.Printf("%6s: %v = %v\n", field.Name, field.Type, value)
}

f1 := v.FieldByIndex([]int{1})
fmt.Println(f1.Interface())

f2 := v.FieldByName("Age")
fmt.Println(f2.Interface())

fmt.Println("Methods:")
for i := 0; i < v.NumMethod(); i++ {
m := t.Method(i)
fmt.Printf("%6s: %v\n", m.Name, m.Type)
}

m1 := v.MethodByName("Say")
args := []reflect.Value{reflect.ValueOf("Hi")}
m1.Call(args)
}

func Set(o interface{}) {
v := reflect.ValueOf(o)

if v.Kind() != reflect.Ptr {
fmt.Println("Not a pointer interface")
return
}

if !v.Elem().CanSet() {
fmt.Println("Can not be set")
return
}

v = v.Elem()
f := v.FieldByName("Age")

if !f.IsValid() {
fmt.Println("Can not find this field")
return
}

if f.Kind() == reflect.Uint8 {
f.SetUint(25)
}
}

3.2 处理结构体匿名字段或嵌入字段

反射匿名或嵌入字段:匿名字段当独立字段处理

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
type User struct {
Id int
Name string
Age byte
}

type Manager struct {
User
Title string
}

func main() {
m := Manager{User: User{1, "Jack", 21}, Title: "CEO"}
t := reflect.TypeOf(m)

fmt.Printf("%#v\n", t.Field(0)) // {Name:"User", ..., Anonymous:true}
fmt.Printf("%#v\n", t.Field(1)) // {Name:"Title", ..., Anonymous:false}

fmt.Printf("%#v\n", t.FieldByIndex([]int{0})) // Same as t.Field(0),{Name:"User", ..., Anonymous:true}
fmt.Printf("%#v\n", t.FieldByIndex([]int{0, 1})) // {Name:"Name", ..., Anonymous:false}

field, ok := t.FieldByName("Title")
if ok {
fmt.Printf("%#v\n", field) // {Name:"Title", ..., Anonymous:false}
}

field, ok = t.FieldByName("Id")
if ok {
fmt.Printf("%#v\n", field) // {Name:"Id", ..., Anonymous:false}
}
}

3.3 通过反射,修改内容

传入的值必选是pointer-interface

1
2
3
4
5
6
7
8
func main() {
x := 10
v := reflect.ValueOf(&x) // ptr-interface
fmt.Printf("%#v\n", v)

v.Elem().SetInt(99)
fmt.Println(x)
}

3.4 通道对象设置

1
2
3
4
5
6
7
8
func main() {
ch := make(chan int, 4)
v := reflect.ValueOf(ch)

if v.TrySend(reflect.ValueOf(100)) {
fmt.Println(v.TryRecv()) // 100 true
}
}

3.5 空接口判断

1
2
3
4
5
6
7
func main() {
var a interface{} = nil
var b interface{} = (*int)(nil)

fmt.Println(a == nil) // true
fmt.Println(b == nil, reflect.ValueOf(b).IsNil()) //false true
}

4. 方法

4.1 调用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
type X struct{}

func (X) Add(x, y int) int {
return x + y
}

func main() {
var a X

v := reflect.ValueOf(a)
m := v.MethodByName("Add")

args := []reflect.Value{
reflect.ValueOf(5),
reflect.ValueOf(7),
}

result := m.Call(args)
for _, val := range result {
fmt.Println(val)
}
}

4.2 调用变参方法

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
type X struct{}

func (X) Format(format string, a ...interface{}) string {
return fmt.Sprintf(format, a...)
}

func main() {
var a X

v := reflect.ValueOf(a)
m := v.MethodByName("Format")

args := []reflect.Value{
reflect.ValueOf("%s = %d"),
reflect.ValueOf("x"),
reflect.ValueOf(10),
}

result := m.Call(args)
fmt.Println(result) // [x = 10]

args = []reflect.Value{
reflect.ValueOf("%d + %d = %d"),
reflect.ValueOf([]interface{}{1, 2, 1 + 2}),
}
result = m.CallSlice(args)
fmt.Println(result) // [1 + 2 = 3]
}

5. 构建

反射库提供了内置函数 make() 和 new() 的对应操作,例如 MakeFunc()。可用它实现通用模板,适应不同数据类型。

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
func main() {
var intAdd func(x, y int) int
var strAdd func(x, y string) string

makeAdd(&intAdd)
makeAdd(&strAdd)

fmt.Println(intAdd(20, 30))
fmt.Println(strAdd("Hello", "World"))
}

func makeAdd(o interface{}) {
fn := reflect.ValueOf(o).Elem()
v := reflect.MakeFunc(fn.Type(), add)
fn.Set(v)
}

func add(args []reflect.Value) (results []reflect.Value) {
if len(args) == 0 {
return nil
}

var ret reflect.Value

switch args[0].Kind() {
case reflect.Int:
sum := 0
for _, n := range args {
sum += int(n.Int())
}
ret = reflect.ValueOf(sum)
case reflect.String:
ss := make([]string, 0, len(args))
for _, s := range args {
ss = append(ss, s.String())
}
ret = reflect.ValueOf(strings.Join(ss, " "))
}

results = append(results, ret)
return
}

6. 反射相关方法

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
reflect.TypeOf(o)             // reflect.Type
reflect.Type.Name() // 类型名称
reflect.Type.Kind() // 原始类型名称:int, string...

reflect.ValueOf(o) // reflect.Value
reflect.Value.Type() // reflect.Type
reflect.Value.Kind() // 原始类型名称:int, string...(默认整型表示)

// 获取变量值
reflect.Value.Float()
reflect.Value.Int()
reflect.Value.String()
reflect.Value.Bool()
reflect.Value.Interface() // 获取真实值,不关系值的类型

// 指针
ptr.Elem().setInt(99)

// 改变变量的值
reflect.Value.SetInt()
reflect.Value.SetFloat()
reflect.Value.SetString()

// 结构体
reflect.Value.NumField() // 结构体字段个数
reflect.Value.Field(i) // reflect.StructField
reflect.Value.FieldByIndex(i) // reflect.StructField
reflect.Value.FieldByName("field") // reflect.StructField
reflect.StructField.Name // 字段名
reflect.StructField.Type // 字段类型

reflect.Value.NumMethod() // 结构体方法个数
reflect.Value.Method(i) // reflect.Method
reflect.Value.MethodByName("method") // reflect.Method
reflect.Method.Name // 方法名
reflect.Method.Type // 方法类型
reflect.Method.Call(in []Value) // 调用方法

7. 反射的三大定律

7.1 两种类型 Type 和 Value

reflect.Type: 以接口的形式存在

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
type Type interface {
Align() int
FieldAlign() int
Method(int) Method
MethodByName(string) (Method, bool)
NumMethod() int
Name() string
PkgPath() string
Size() uintptr
String() string
Kind() Kind
Implements(u Type) bool
AssignableTo(u Type) bool
ConvertibleTo(u Type) bool
Comparable() bool
Bits() int
ChanDir() ChanDir
IsVariadic() bool
Elem() Type
Field(i int) StructField
FieldByIndex(index []int) StructField
FieldByName(name string) (StructField, bool)
FieldByNameFunc(match func(string) bool) (StructField, bool)
In(i int) Type
Key() Type
Len() int
NumField() int
NumIn() int
NumOut() int
Out(i int) Type
common() *rtype
uncommon() *uncommonType
}

reflect.Value: 以结构体形式存在

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
type Value struct {
typ *rtype
ptr unsafe.Pointer
flag
}

func (v Value) Addr() Value
func (v Value) Bool() bool
func (v Value) Bytes() []byte
func (v Value) Call(in []Value) []Value
func (v Value) CallSlice(in []Value) []Value
func (v Value) CanAddr() bool
func (v Value) CanInterface() bool
func (v Value) CanSet() bool
func (v Value) Cap() int
func (v Value) Close()
func (v Value) Complex() complex128
func (v Value) Convert(t Type) Value
func (v Value) Elem() Value
func (v Value) Field(i int) Value
func (v Value) FieldByIndex(index []int) Value
func (v Value) FieldByName(name string) Value
func (v Value) FieldByNameFunc(match func(string) bool) Value
func (v Value) Float() float64
func (v Value) Index(i int) Value
func (v Value) Int() int64
func (v Value) Interface() (i interface})
func (v Value) InterfaceData() [2]uintptr
func (v Value) IsNil() bool
func (v Value) IsValid() bool
func (v Value) IsZero() bool
func (v Value) Kind() Kind
func (v Value) Len() int
func (v Value) MapIndex(key Value) Value
func (v Value) MapKeys() []Value
func (v Value) MapRange() *MapIter
func (v Value) Method(i int) Value
func (v Value) MethodByName(name string) Value
func (v Value) NumField() int
func (v Value) NumMethod() int
func (v Value) OverflowComplex(x complex128) bool
func (v Value) OverflowFloat(x float64) bool
func (v Value) OverflowInt(x int64) bool
func (v Value) OverflowUint(x uint64) bool
func (v Value) Pointer() uintptr
func (v Value) Recv() (x Value, ok bool)
func (v Value) Send(x Value)
func (v Value) Set(x Value)
func (v Value) SetBool(x bool)
func (v Value) SetBytes(x []byte)
func (v Value) SetCap(n int)
func (v Value) SetComplex(x complex128)
func (v Value) SetFloat(x float64)
func (v Value) SetInt(x int64)
func (v Value) SetLen(n int)
func (v Value) SetMapIndex(key, elem Value)
func (v Value) SetPointer(x unsafe.Pointer)
func (v Value) SetString(x string)
func (v Value) SetUint(x uint64)
func (v Value) Slice(i, j int) Value
func (v Value) Slice3(i, j, k int) Value
func (v Value) String() string
func (v Value) TryRecv() (x Value, ok bool)
func (v Value) TrySend(x Value) bool
func (v Value) Type() Type
func (v Value) Uint() uint64
func (v Value) UnsafeAddr() uintptr
func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value
func (v Value) call(op string, in []Value) []Value
func (v Value) pointer() unsafe.Pointer
func (v Value) recv(nb bool) (val Value, ok bool)
func (v Value) runes() []rune
func (v Value) send(x Value, nb bool) (selected bool)
func (v Value) setRunes(x []rune)

7.2 反射的三大定律

  • Reflection goes from interface value to reflection object.

  • 反射可以将接口类型变量 转换为“反射类型对象”

  • Reflection goes from reflection object to interface value.

  • 反射可以将 “反射类型对象”转换为 接口类型变量

  • To modify a reflection object, the value must be settable.

  • 如果要修改 “反射类型对象” 其类型必须是 可写的

7.2.1 第一定律

Reflection goes from interface value to reflection object.

  • reflect.TypeOf(i): 获取接口值的类型 (*reflect.rtype)
  • reflect.ValueOf(i): 获取接口值的值 (reflect.Value)

reflect_1

7.2.2 第二定律

Reflection goes from reflection object to interface value.

reflect_2

注意:只有Value才能逆向转换,Type则不行

1
2
3
func (v Value) Interface() (i interface{}) {
return valueInterface(v, true)
}

reflect_1_2

7.2.3 第三定律

To modify a reflection object, the value must be settable.

  • 非指针变量创建的反射对象,不可写
  • CanSet()返回true,为可写对象
  • 不可写对象,无法进行写操作
  • 可写对象,使用Elem()函数返回指针指向的数据
1
2
3
4
5
6
7
8
9
10
11
12
func main() {
var name string = "Go编程"

v1 := reflect.ValueOf(name)
fmt.Println(v1.CanSet()) // false, 使用v1.Elem()方法会触发异常

v2 := reflect.ValueOf(&name)
fmt.Println(v2.CanSet()) // false

v3 := v2.Elem()
fmt.Println(v3.CanSet()) // true
}

可写对象的相关方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
Set(x Value)
SetBool(x bool)
SetBytes(x []byte)
setRunes(x []rune)
SetComplex(x complex128)
SetFloat(x float64)
SetInt(x int64)
SetLen(n int)
SetCap(n int)
SetMapIndex(key Value, elem Value)
SetUint(x uint64)
SetPointer(x unsafe.Pointer)
SetString(x string)