🌙 1.反射概述
反射是指在程序运行期对程序本身进行访问和修改的能力,即可以在运行时动态获取变量的各种信息,比如变量的类型(type),值(value),如果是结构体变量,还可以获取到结构体本身的信息(字段与方法),通过反射,还可以修改变量的值,可以调用关联的方法。
每种语言的反射模型都不同,并且有些语言根本不支持反射。
Go语言实现了反射,反射机制就是在运行时动态调用对象的方法和属性,即可从运行时态的示例对象反求其编码阶段的定义。
注意:
- 在编译期间,无法对反射代码进行一些错误提示。
- 反射影响性能
🌙 2.反射方法
标准库中reflect
包提供了相关的功能。在reflect
包中,通过reflect.TypeOf()
,reflect.ValueOf()
分别从类型、值的角度来描述一个Go对象。
// TypeOf returns the reflection Type that represents the dynamic type of i.
// If i is a nil interface value, TypeOf returns nil.
func TypeOf(i interface{}) Type {...}
// ValueOf returns a new Value initialized to the concrete value
// stored in the interface i. ValueOf(nil) returns the zero Value.
func ValueOf(i interface{}) Value {...}
1
2
3
4
5
6
7
2
3
4
5
6
7
在Go语言的实现中,一个interface
类型的变量存储了2类信息, <value,type>
:
- value 是变量的值。
reflect.ValueOf
获取变量的值,返回值Value
类型 - type 是变量的类型。
reflect.TypeOf
获取变量的类型,返回值Type
类型、即concrete type
func testDemo1() {
var x float32 = 3.14
v := reflect.ValueOf(x)
t := reflect.TypeOf(x)
fmt.Println(v) // 返回Value类型对象,值为3.14
fmt.Println(t) // 返回Type类型对象,值为float32
}
1
2
3
4
5
6
7
2
3
4
5
6
7
🌙 3.方法返回值类型
// Value 结构体
type Value struct {...}
// Type returns v's type.
func (v Value) Type() Type {...}
func (v Value) Kind() Kind {...}
... ...
// Type 接口
type Type interface {
// NumMethod returns the number of methods accessible using Method.
//
// Note that NumMethod counts unexported methods only for interface types.
NumMethod() int
// Name returns the type's name within its package for a defined type.
// For other (non-defined) types it returns the empty string.
Name() string
// Kind returns the specific kind of this type.
Kind() Kind
// Elem returns a type's element type.
// It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.
Elem() 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
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
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func testDemo2() {
var p1 = Person{"zkk", 17}
v1 := reflect.ValueOf(p1)
t1 := reflect.TypeOf(p1) // main.Person
fmt.Println("**************Person**************")
fmt.Println(v1) // {zkk 17}
fmt.Println(t1) // main.Person
fmt.Println("v1.Type()", v1.Type()) // v1.Type() main.Person
fmt.Println("v1.Kind()", v1.Kind()) // v1.Kind() struct
fmt.Println("t1.Kind()", t1.Kind()) // t1.Kind() struct
fmt.Println("t1.Name()", t1.Name()) // t1.Name() Person
//fmt.Println("t1.Elem()", t1.Elem()) // error panic
fmt.Println("**************&Person**************")
var p2 = &Person{"zkk", 18}
v2 := reflect.ValueOf(p2)
t2 := reflect.TypeOf(p2)
fmt.Println(v2) // &{zkk 18}
fmt.Println(t2) // *main.Person
fmt.Println("v2.Type()", v2.Type()) // v2.Type() *main.Person
fmt.Println("v2.Kind()", v2.Kind()) // v2.Kind() ptr
fmt.Println("t2.Kind()", t2.Kind()) // t2.Kind() ptr
fmt.Println("t2.Name()", t2.Name()) // t2.Name() '' 空字符串
fmt.Println("t2.Elem()", t2.Elem()) // t2.Elem() main.Person
}
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
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
类型Type()
与种类Kind()
的区别:
reflect.ValueOf(p).Type()
是原生数据类型:int
、string
、bool
、float32
,以及type
定义的类型,对应的反射获取方法是reflect.Type
中 的Name()
reflect.TypeOf(p).Kind()
是对象归属的品种:Int
、Bool
、Float32
、Chan
、String
、Struct
、Ptr
(指针)、Map
、Interface
、Func
、Array
、Slice
、Unsafe Pointer
等
type Kind uint
const (
Invalid Kind = iota
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Ptr
Slice
String
Struct
UnsafePointer
)
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
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
🌙 4.静态类型和动态类型
- 静态类型:变量声明时候赋予的类型
type MyInt int // int 是静态类型
var i *int // *int 是静态类型
1
2
2
- 动态类型:运行时给这个变量赋值时,这个值的类型即为动态类型(为
nil
时没有动态类型)。
空接口是静态类型,必须是接口类型才能实现类型动态变化
var A interface{} // 静态类型
A = 10 // 此时静态类型为 interface{} 动态为int
A = "hello" // 此时静态类型为 interface{} 动态为string
1
2
3
2
3
🌙 5.反射三大定律
- 1.反射可以将接口类型变量 转换为“反射类型对象”;
- 2.反射可以将 “反射类型对象”转换为 接口类型变量;
- 3.如果要修改 “反射类型对象” 其类型必须是 可写的
CanSet()
;
🌙 5.反射的应用
反射常用在框架的开发上,一些常见的案例,如JSON序列化时候tag标签的产生,适配器函数的制作等,都需要用到反射。
反射的两个常见使用场景:
- 不知道函数的参数类型:没有约定好参数、传入类型很多,此时类型不能统一表示,需要反射
- 不知道调用哪个函数:比如根据用户的输入来决定调用特定函数,此时需要依据函数、函数参数进行反射,在运行期间动态执行函数
🌙 5.1操作简单数据类型
func testDemo3() {
var n int64 = 111
// 设置值,指针传递
// 定律1:反射可以将接口类型变量 转换为“反射类型对象”
ptrValue := reflect.ValueOf(&n)
// Elem()用于获取原始值的反射对象
newValue := ptrValue.Elem()
fmt.Println("type:", newValue.Type()) // type: int64
// 是否可写can set
// 定律3:当反射对象所存的值是可设置时,反射对象才可修改
fmt.Println("can set:", newValue.CanSet()) // can set: true
newValue.SetInt(666) // 修改为666
// 获取值,值传递
nv := reflect.ValueOf(n)
fmt.Println(nv.Int()) // 666
// 定律2:反射可以将 “反射类型对象”转换为 接口类型变量;
fmt.Println(nv.Interface().(int64)) // 666
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
🌙 5.2进行类型推断
func checkType(i interface{}) {
t := reflect.TypeOf(i)
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
fmt.Println("Int number")
case reflect.Float32, reflect.Float64:
fmt.Println("Float number")
case reflect.String:
fmt.Println("String")
case reflect.Slice:
fmt.Println("Slice")
case reflect.Map:
fmt.Println("Map")
case reflect.Struct:
fmt.Println("Struct")
default:
fmt.Printf("Unknown %v\n", t)
}
}
func getInfo(i interface{}) {
t := reflect.TypeOf(i)
fmt.Printf("%v\n", t)
v := reflect.ValueOf(i)
fmt.Printf("%v\n", v)
if k := t.Kind(); k != reflect.Struct {
fmt.Println("Input Type is not Struct")
return
}
for j := 0; j < t.NumField(); j++ {
f := t.Field(j)
fv := v.Field(j).Interface()
fmt.Printf("%8s %v=%v\n", f.Name, f.Type, fv)
}
}
type User struct {
Name string
Age int
Gender string
}
func (u *User) Greet(msg string) {
fmt.Printf("My name is %s, age %d, msg:%v\n", u.Name, u.Age, msg)
}
func testDemo6() {
u := User{Age: 18, Name: "JEEK", Gender: "female"}
checkType(u) // Struct
checkType(&u) // Unknown *main.User
getInfo(u)
/* main.User
{JEEK 18 female}
Name string=JEEK
Age int=18
Gender string=man
*/
}
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
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
🌙 5.3创建slice、map、chan
func testDemo5() {
// 反射创建map slice channel
intSlice := make([]int, 0)
mapStringInt := make(map[string]int)
sliceType := reflect.TypeOf(intSlice)
mapType := reflect.TypeOf(mapStringInt)
// 创建新值
intSliceReflect := reflect.MakeSlice(sliceType, 0, 0)
mapReflect := reflect.MakeMap(mapType)
// 使用新创建的变量
n := 11
nv := reflect.ValueOf(n)
intSliceReflect = reflect.Append(intSliceReflect, nv)
intSlice1 := intSliceReflect.Interface().([]int)
fmt.Println(intSlice1) // [11]
k := "hello"
kv := reflect.ValueOf(k)
mapReflect.SetMapIndex(kv, nv)
mapStringInt1 := mapReflect.Interface().(map[string]int)
fmt.Println(mapStringInt1) // map[hello:11]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
🌙 5.4创建函数
func createTimedFunc(i interface{}) interface{} {
rt := reflect.TypeOf(i)
if rt.Kind() != reflect.Func {
panic("not Reflect.Func")
}
rv := reflect.ValueOf(i)
wf := reflect.MakeFunc(rt, func(in []reflect.Value) []reflect.Value {
st := time.Now()
rt := rv.Call(in)
et := time.Now()
fmt.Printf("execute %s took %v\n", runtime.FuncForPC(rv.Pointer()).Name(), et.Sub(st))
return rt
})
return wf.Interface()
}
func test1() {
fmt.Println("test1 start")
time.Sleep(time.Second * 2)
fmt.Println("test1 end")
}
func test2(n int) int {
fmt.Println("test2 start")
time.Sleep(time.Duration(n) * time.Second)
fmt.Println("test2 end")
return n
}
func testDemo7() {
timedTest1 := createTimedFunc(test1).(func())
timedTest1()
timedTest2 := createTimedFunc(test2).(func(int) int)
fmt.Println(timedTest2(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
32
33
34
35
36
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
结果:
test1 start
test1 end
execute main.test1 took 2.0100738s
test2 start
test2 end
execute main.test2 took 4.0011527s
4
1
2
3
4
5
6
7
2
3
4
5
6
7
reflect.Value.Call (var)
源码:
// Call calls the function v with the input arguments in.
// For example, if len(in) == 3, v.Call(in) represents the Go call v(in[0], in[1], in[2]).
// Call panics if v's Kind is not Func.
// It returns the output results as Values.
// As in Go, each input argument must be assignable to the
// type of the function's corresponding input parameter.
// If v is a variadic function, Call creates the variadic slice parameter
// itself, copying in the corresponding values.
func (v Value) Call(in []Value) []Value {
v.mustBe(Func)
v.mustBeExported()
return v.call("Call", in)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
🌙 5.5操作结构体
type User struct {
Name string `json:"name" tag:"姓名"`
Age int `json:"age" tag:"年龄"`
Gender string `json:"gender" tag:"性别"`
}
func (u *User) Greet(msg string) {
fmt.Printf("My name is %s, age %d, msg:%v\n", u.Name, u.Age, msg)
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
下面通过reflect
来操作结构体User
- 字段读取
func testDemo8() {
u := User{Age: 18, Name: "JEEK", Gender: "Female"}
t := reflect.TypeOf(u)
v := reflect.ValueOf(u)
fmt.Printf("%v\n", t.Field(0)) // {Name string 0 [0] false}
fmt.Printf("%v\n", v.FieldByName("Gender")) // Female
// 读取tag
f := t.Field(1) // Age
fmt.Printf("f.tag: %s\n", f.Tag) // json:"age" tag:"年龄"
fmt.Printf("f.tag get: %s\n", f.Tag.Get("json")) // age
tag, _ := f.Tag.Lookup("tag")
fmt.Printf("f.tag Lookup: %s\n", tag) // 年龄
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- 方法调用
func testDemo9() {
u := &User{Age: 18, Name: "JEEK", Gender: "Female"}
v := reflect.ValueOf(u)
m := v.MethodByName("Greet")
args := []reflect.Value{reflect.ValueOf("Hello world!")}
m.Call(args) // My name is JEEK, age 18, msg:Hello world!
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
🌙 5.6综合案例
type ss struct {
int
string
bool
float64
}
func (s ss) Method1(i int) string {
return "结构体方法1:值接收器"
}
func (s *ss) Method2(i int) string {
return "结构体方法2:指针接收器"
}
var structValue = ss{
20,
"结构体",
true,
3.14,
}
var complexTypes = []interface{}{
structValue,
&structValue,
}
func printInfo(i interface{}) {
if i == nil {
fmt.Printf("----------------------------")
fmt.Printf("无效的接口值:%v\n", i)
fmt.Println("----------------------------")
return
}
fmt.Printf("\n---------------【%#v】-----------------\n", i)
v := reflect.ValueOf(i)
printValue(v)
}
func printValue(v reflect.Value) {
fmt.Println("反射值字符串[reflect.ValueOf(i).String()] :", v.String())
fmt.Println("反射值类型[reflect.ValueOf(i).Type()] :", v.Type())
fmt.Println("反射值类别[reflect.ValueOf(i).Kind()] :", v.Kind())
fmt.Println("是否可取址[reflect.ValueOf(i).CanAddr()] :", v.CanAddr())
fmt.Println("是否可修改[reflect.ValueOf(i).CanSet()] :", v.CanSet())
if v.CanAddr() {
fmt.Println("获取地址[reflect.ValueOf(i).Addr()] :", v.Addr())
fmt.Println("获取自由地址[reflect.ValueOf(i).UnsafeAddr()] :", v.UnsafeAddr())
}
fmt.Println("获取方法数量[reflect.ValueOf(i).NumMethod()] :", v.NumMethod())
if v.NumMethod() > 0 {
i := 0
for ; i < v.NumMethod()-1; i++ {
fmt.Printf(" ├ %v\n", v.Method(i).String())
}
fmt.Printf(" └ %v\n", v.Method(i).String())
}
fmt.Println("通过名称获取方法1[(reflect.ValueOf(i).MethodByName(Method1))] :", v.MethodByName("Method1").String())
fmt.Println("通过名称获取方法2[(reflect.ValueOf(i).MethodByName(Method2))] :", v.MethodByName("Method2").String())
switch v.Kind() {
case reflect.Struct:
fmt.Println("==========结构体==========")
fmt.Println("结构体字段个数[(reflect.ValueOf(i).NumField())]:", v.NumField())
if v.NumField() > 0 {
var i int
for i = 0; i < v.NumField()-1; i++ {
field := v.Field(i)
fmt.Printf(" ├ %-8v %v\n", field.Type(), field.String())
}
field := v.Field(i)
fmt.Printf(" └ %-8v %v\n", field.Type(), field.String())
}
}
}
func testDemo10() {
for i := 0; i < len(complexTypes); i++ {
printInfo(complexTypes[i])
}
}
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
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
结果:
---------------【main.ss{int:20, string:"结构体", bool:true, float64:3.14}】-----------------
反射值字符串[reflect.ValueOf(i).String()] : <main.ss Value>
反射值类型[reflect.ValueOf(i).Type()] : main.ss
反射值类别[reflect.ValueOf(i).Kind()] : struct
是否可取址[reflect.ValueOf(i).CanAddr()] : false
是否可修改[reflect.ValueOf(i).CanSet()] : false
获取方法数量[reflect.ValueOf(i).NumMethod()] : 1
└ <func(int) string Value>
通过名称获取方法1[(reflect.ValueOf(i).MethodByName(Method1))] : <func(int) string Value>
通过名称获取方法2[(reflect.ValueOf(i).MethodByName(Method2))] : <invalid Value>
==========结构体==========
结构体字段个数[(reflect.ValueOf(i).NumField())]: 4
├ int <int Value>
├ string 结构体
├ bool <bool Value>
└ float64 <float64 Value>
---------------【&main.ss{int:20, string:"结构体", bool:true, float64:3.14}】-----------------
反射值字符串[reflect.ValueOf(i).String()] : <*main.ss Value>
反射值类型[reflect.ValueOf(i).Type()] : *main.ss
反射值类别[reflect.ValueOf(i).Kind()] : ptr
是否可取址[reflect.ValueOf(i).CanAddr()] : false
是否可修改[reflect.ValueOf(i).CanSet()] : false
获取方法数量[reflect.ValueOf(i).NumMethod()] : 2
├ <func(int) string Value>
└ <func(int) string Value>
通过名称获取方法1[(reflect.ValueOf(i).MethodByName(Method1))] : <func(int) string Value>
通过名称获取方法2[(reflect.ValueOf(i).MethodByName(Method2))] : <func(int) string 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
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
可以发现structValue
,&structValu
e的反射结果是不一样的,指针对象在这里有两个方法,而值对象只有一个方法,这是因为Method2()方法是指针方法,在值对象中是不能被反射到的。