reflectreflect.Valuereflect.Type

为了方便演示操作(完整代码示例),首先定义以下结构体以及字段、方法:

1
2
3
4
5
6
7
8
9
10
type User struct {
Name string `json:"name"`
Age int `json:"age" default:"18"`
addr string `json:"addr"`
}

func (u User) Do(in string) (string, int) {
fmt.Printf("%s Name is %s, Age is %d \n", in, u.Name, u.Age)
return u.Name, u.Age
}

一、反射对象 Value 和 Type

ValueType
reflectreflect.ValueOf()reflect.TypeOf()interface{}ValueType
1
2
3
4
5
6
7
u := User{"tom", 27, "beijing"}

v := reflect.ValueOf(u)
fmt.Println(v)

t := reflect.TypeOf(u)
fmt.Println(t)
ValueValue.Type()Type
1
2
t1 := v.Type()
fmt.Println(t == t1)
true
TypeValue
1
2
v1 := reflect.New(t)
fmt.Println(v1)
&{ 0}

二、反射对象的 Kind

KindType
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 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
)
Value.Kind()Type.Kind()
1
2
3
4
5
6
7
// 获取 Kind 类型
k := t.Kind()
fmt.Println(k)
k1 := v.Kind()
fmt.Println(k1)
fmt.Println(k == k1)
fmt.Println()
struct

三、反射对象的字段

反射能够操作的字段和方法必须是可导出(首字母大写)的。

ValueElem()Value
Elem()func (v Value) Elem() ValuevvvKindInterfacePtr
reflect.Indirect()ValueElem()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
// 修改反射对象的值
i := 20
fmt.Println("before i =", i)
e := reflect.Indirect(reflect.ValueOf(&i))
// e := reflect.ValueOf(&i).Elem()
if e.CanSet() {
e.SetInt(22)
}
fmt.Println("after i =", i)


// 反射字段操作
// elem := reflect.Indirect(reflect.ValueOf(&u))
elem := reflect.ValueOf(&u).Elem()
for i := 0; i < t.NumField(); i++ {
// 反射获取字段的元信息,例如:名称、Tag 等
ft := t.Field(i)
fmt.Println("field name:", ft.Name)
tag := ft.Tag
fmt.Println("Tag:", tag)
fmt.Println("Tag json:", tag.Get("json"))

// 反射修改字段的值
fv := elem.Field(i)
if fv.CanSet() {
if fv.Kind() == reflect.Int {
fmt.Println("change age to 30")
fv.SetInt(30)
}
if fv.Kind() == reflect.String {
fmt.Println("change name to jerry")
fv.SetString("jerry")
}
}
fmt.Println()
}
fmt.Println("after user:", u)

四、反射对象的方法

ValueMethod()TypeMethod()
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
// 反射方法操作
for i := 0; i < v.NumMethod(); i++ {
method := t.Method(i) // 获取方法信息对象,方法 1
mt := method.Type // 获取方法信息 Type 对象,方法 1

// m := v.Method(i) // 获取方法信息对象,方法 2
// mt := m.Type() // 获取方法信息 Type 对象,方法 2

fmt.Println("method name:", method.Name)

in := []reflect.Value{}

// 获取方法入参类型
for j := 0; j < mt.NumIn(); j++ {
fmt.Println("method in type:", mt.In(j))
if mt.In(j).Kind() == reflect.String {
in = append(in, reflect.ValueOf("welcome"))
}
// 方法 1 获取的方法信息对象会把方法的接受者也当着入参之一
if mt.In(j).Name() == t.Name() {
in = append(in, v)
}
}

// 获取方法返回类型
for j := 0; j < mt.NumOut(); j++ {
fmt.Println("method out type:", mt.Out(j))
}

// 反射方法调用
// out := m.Call(in) // 方法 1 获取的 Method 对象反射调用方式
out := method.Func.Call(in) // 方法 1 获取的 Method 对象反射调用方式
for _, o := range out {
fmt.Println("out:", o)
}
}

五、反射对象 Value 还原

reflect.ValueOf()ValueValueInterface()Value
1
2
3
4
// Value 转原始类型
if u1, ok := v.Interface().(User); ok {
fmt.Println("after:", u1.Name, u1.Age)
}