Golang反射reflect解析
反射基本函数
reflect.Type
主要提供关于类型相关的信息,所以它和 _type 关联比较紧密;
reflect.Value
则结合 _type
和 data
两者,因此可以获取甚至改变类型的值。
1 | func TypeOf(i interface{}) Type // 返回i的对象类型 |
TypeOf
1 | func TypeOf(i interface{}) Type { |
- 将先将
i
转换成*emptyInterface
类型,然後在返回typ
字段,rtype
实现了Type
接口
ValueOf
1 | func ValueOf(i interface{}) Value { |
- 将先将
i
转换成*emptyInterface
类型, 再将它的typ
字段和word
字段以及一个标志位字段组装成一个Value
结构体,而这就是ValueOf
函数的返回值,它包含类型结构体指针、真实数据的地址、标志位。
Type
1 | type Type interface { |
使用示例
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129package main
import (
"fmt"
"reflect"
)
type FooIF interface {
DoSomething()
DoSomethingWithArg(a string)
DoSomethingWithUnCertenArg(a ... string)
}
type Foo struct {
A int
B string
C struct {
C1 int
}
}
func (f *Foo) DoSomething() {
fmt.Println(f.A, f.B)
}
func (f *Foo) DoSomethingWithArg(a string) {
fmt.Println(f.A, f.B, a)
}
func (f *Foo) DoSomethingWithUnCertenArg(a ... string) {
fmt.Println(f.A, f.B, a[0])
}
func (f *Foo) returnOneResult() int {
return 2
}
func main() {
var simpleObj Foo
var pointer2obj = &simpleObj
var simpleIntArray = [3]int{1, 2, 3}
var simpleMap = map[string]string{
"a": "b",
}
var simpleChan = make(chan int, 1)
var x uint64
var y uint32
varType := reflect.TypeOf(simpleObj)
varPointerType := reflect.TypeOf(pointer2obj)
// 对齐之后要多少容量
fmt.Println("Align: ", varType.Align())
// 作为结构体的`field`要对其之后要多少容量
fmt.Println("FieldAlign: ", varType.FieldAlign())
// 类型名称
fmt.Println("Name: ", varType.Name())
// 绝对引入路径
fmt.Println("PkgPath: ", varType.PkgPath())
// 实际上用了多少内存
fmt.Println("Size: ", varType.Size())
// 类型的类型值
fmt.Println("Kind: ", varType.Kind())
// 有多少函数(指针对象能获取全部函数,非指针的只能获取非指针函数)
fmt.Println("NumMethod: ", varPointerType.NumMethod())
// 通过名字获取一个函数
m, success := varPointerType.MethodByName("DoSomethingWithArg")
if success { // 调用该方法
m.Func.Call([]reflect.Value{
reflect.ValueOf(pointer2obj),
reflect.ValueOf("sad"),
})
}
// 通过索引获取函数
m = varPointerType.Method(1)
m.Func.Call([]reflect.Value{ // 调用该方法
reflect.ValueOf(pointer2obj),
reflect.ValueOf("sad2"),
})
// 是否实现了某个接口
fmt.Println("Implements:", varPointerType.Implements(reflect.TypeOf((*FooIF)(nil)).Elem()))
// 看看指针多少bit
fmt.Println("Bits: ", reflect.TypeOf(x).Bits())
// 查看array, chan, map, ptr, slice的元素类型
fmt.Println("Elem: ", reflect.TypeOf(simpleIntArray).Elem().Kind())
// 查看Array长度
fmt.Println("Len: ", reflect.TypeOf(simpleIntArray).Len())
// 查看结构体类型的第 i 个字段
fmt.Printf("Field: %+v \n", varType.Field(1))
// 查看嵌套的结构体的字段
fmt.Printf("FieldByIndex %+v \n", varType.FieldByIndex([]int{2, 0}))
// 通过字段名称获取字段
fi, success2 := varType.FieldByName("A")
if success2 {
fmt.Printf("FieldByName: %+v \n", fi)
}
// 查看名称符合 func 函数的字段
fi, success2 = varType.FieldByNameFunc(func(fieldName string) bool {
return fieldName == "A"
})
if success2 {
fmt.Printf("FieldByName: %+v \n", fi)
}
// 查看结构体数量
fmt.Println("NumField", varType.NumField())
// 查看map的key类型
fmt.Println("Key: ", reflect.TypeOf(simpleMap).Key().Name())
// 查看函数有多少个参数
fmt.Println("NumIn: ", reflect.TypeOf(pointer2obj.DoSomethingWithUnCertenArg).NumIn())
// 查看函数参数的类型
fmt.Println("In: ", reflect.TypeOf(pointer2obj.DoSomethingWithUnCertenArg).In(0))
// 查看最后一个参数,是否解构了
fmt.Println("IsVariadic: ", reflect.TypeOf(pointer2obj.DoSomethingWithUnCertenArg).IsVariadic())
// 查看函数有多少输出
fmt.Println("NumOut: ", reflect.TypeOf(pointer2obj.DoSomethingWithUnCertenArg).NumOut())
// 查看函数输出的类型
fmt.Println("Out: ", reflect.TypeOf(pointer2obj.returnOneResult).Out(0))
// 查看通道的方向, 3双向。
fmt.Println("ChanDir: ", int(reflect.TypeOf(simpleChan).ChanDir()))
// 查看该类型是否可以比较。不能比较的slice, map, func
fmt.Println("Comparable: ", varPointerType.Comparable())
// 查看类型是否可以转化成另外一种类型
fmt.Println("ConvertibleTo: ", varPointerType.ConvertibleTo(reflect.TypeOf("a")))
// 该类型的值是否可以另外一个类型
fmt.Println("AssignableTo: ", reflect.TypeOf(x).AssignableTo(reflect.TypeOf(y)))
}
value
Value 字段还有很多方法,可以去看文档: http://docscn.studygolang.com/pkg/reflect/,或者去src/reflect/value.go
看看源码,搜索 func(v Value)
就能看到。
1 | value.CanSet()返回值能否更改 |
StructField
结构的字段具有很多特殊信息,定义了StructField
类型来表示一个字段
1 | func NumField() int //结构字段数量 |
StructTag
描述了结构字段的tag
1
2
3
4
5
6
7tag格式为:
* 由多个部分连接而成,部分之间有可选的空格
* 部分格式为 key:value
* key是非空的字符串,由非控制字符组成,并且不可以是空格、双引号、冒号
* 值由双引号包围,遵循Go字符串字面值语法
func (tag StructTag) Get(key string) string //将一个tag看做映射,各个部分就是映射的元素Kind
reflect包使用Kind类型来表示类型所属的分类
反射的三大定律
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.
- 反射可以从接口类型到反射类型对象
- 反射是一种检测存储在 interface 中的类型和值机制。这可以通过 TypeOf 函数和 ValueOf 函数得到。
- 反射可以从接口类型到反射类型对象
- 反射可以从反射类型对象到接口类
- 将 ValueOf 的返回值通过 Interface()函数反向转变成 interface 变量
- 反射可以从反射类型对象到接口类
- 修改反射类型变量的内部值需要保证其可设置性
- 如果想要操作原变量,反射变量 Value 必须要使用原变量的地址才行。
- 修改反射类型变量的内部值需要保证其可设置性
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Chc-个人数据程序主页!