go反射教程
1. 简单示例
需求:给定一个结构体,判断其字段类型并进行修改
package main
import (
"fmt"
"reflect"
)
type MyInt int
type User struct {
IdOrName any `json:"idOrName"`
M MyInt `json:"m"`
}
func main() {
str := 1
u := User{IdOrName: str, M: 20}
valueOf := reflect.ValueOf(&u).Elem()
elem := valueOf.FieldByName("IdOrName")
elem2 := valueOf.FieldByName("M")
fmt.Println(elem2.Type())
fmt.Println(elem2.Kind())
if elem.Kind() == reflect.Interface {
if elem.Elem().Kind() == reflect.String {
elem.Set(reflect.ValueOf("这是string类型,所以是名字"))
}
if elem.Elem().Kind() == reflect.Int ||
elem.Elem().Kind() == reflect.Int64 ||
elem.Elem().Kind() == reflect.Int32 {
elem.Set(reflect.ValueOf(1000))
}
}
fmt.Println(u)
//如果想要获取字段相关的信息,使用TypeOf
typeOf := reflect.TypeOf(u)
for i := 0; i < typeOf.NumField(); i++ {
field := typeOf.Field(i)
fmt.Println("name:", field.Name)
fmt.Println("type:", field.Type)
fmt.Println("kind:", field.Type.Kind())
fmt.Println("tag:", field.Tag)
}
}
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
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
从上述案例中,我们可以了解一些基本的知识:
- 获取值使用ValueOf
- 获取元素使用Elem
- 判断类型使用Kind或者Type,如果类型使用type定义,Kind返回的是底层类型
- 设置值使用Set
- 如果想修改值,必须为指针类型
- 如果想要获取结构体信息或者类型,可以使用TypeOf
2. 反射定义
简单讲:反射就是在程序运行时,可以访问自身结构并且做出修改的一种能力(审视自身)。
在golang中,反射是通过reflect
包来实现。
反射是建立在类型系统上的,以下是go中空接口interface{}
的定义:
//runtime/runtime2.go
type eface struct {
_type *_type //类型信息
data unsafe.Pointer//数据信息,指向数据指针
}
1
2
3
4
5
2
3
4
5
这里面包含两个重要的变量:
- 类型
- 值
对应到反射中,有两个方法:
reflect.TypeOf
:获取类型信息,返回Type
类型reflect.ValueOf()
获取数据信息,返回Value
类型。
// ValueOf returns a new Value initialized to the concrete value
// stored in the interface i. ValueOf(nil) returns the zero Value.
func ValueOf(i any) Value {}
// 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 any) Type {}
1
2
3
4
5
6
2
3
4
5
6
go反射中,都是通过将
interface{}
转换为Type或者Value类型,然后通过对Type和Value的操作,来实现相应的功能
3. 反射三定律
在2011年的官方一篇博客中,有描述反射的三个定律:
地址:https://go.dev/blog/laws-of-reflection
- 第一定律:反射从接口值转变为反射对象(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)
package main
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.14
//第一定律
fmt.Println("type:", reflect.TypeOf(x))
//第二定律
xValueOf := reflect.ValueOf(x)
y := xValueOf.Interface().(float64)
fmt.Println("y=", y)
//第三定律
//这个会报错
//xValueOf.SetFloat(7.1)
pointValueOf := reflect.ValueOf(&x)
elem := pointValueOf.Elem()
elem.SetFloat(7.1)
fmt.Println("x=", x)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
4. Kind
在前面我们提到,Kind返回一个类型,返回的类型在reflect包有定义:
// A Kind represents the specific kind of type that a Type represents.
// The zero Kind is not a valid kind.
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
Pointer
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
32
33
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
5. reflect.Type
通过TypeOf获取到Type类型后,就可以获取类型相关的一些信息,比如Slice长度,struct成员信息,函数参数等
5.1 Struct
5.1.1 获取成员变量信息
package main
import (
"fmt"
"reflect"
)
type User struct {
UserName string `json:"userName"`
Age int `json:"age"`
Gender string `json:"gender"`
}
func main() {
var user = User{
UserName: "mszlu",
Age: 18,
Gender: "男",
}
typeUser := reflect.TypeOf(user)
numField := typeUser.NumField()
for i := 0; i < numField; i++ {
field := typeUser.Field(i)
fmt.Printf("%d : name(变量名称)=%s offset(首地址偏移量)=%d \n"+
"anonymous(是否为匿名变量)=%t type(变量类型)=%s exported(是否可见)=%t tag=%s\n",
i, field.Name,
field.Offset,
field.Anonymous,
field.Type,
field.IsExported(),
field.Tag,
)
}
//除了上述方式,也可以使用变量名称获取字段
if un, ok := typeUser.FieldByName("UserName"); ok {
fmt.Printf("name(变量名称)=%s offset(首地址偏移量)=%d \n"+
"anonymous(是否为匿名变量)=%t type(变量类型)=%s exported(是否可见)=%t tag=%s\n",
un.Name,
un.Offset,
un.Anonymous,
un.Type,
un.IsExported(),
un.Tag,
)
}
//还可以根据索引获取
age := typeUser.FieldByIndex([]int{1})
fmt.Printf("name(变量名称)=%s offset(首地址偏移量)=%d \n"+
"anonymous(是否为匿名变量)=%t type(变量类型)=%s exported(是否可见)=%t tag=%s\n",
age.Name,
age.Offset,
age.Anonymous,
age.Type,
age.IsExported(),
age.Tag,
)
}
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
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
5.1.2 获取方法信息
package main
import (
"fmt"
"reflect"
)
type User struct {
UserName string `json:"userName"`
Age int `json:"age"`
Gender string `json:"gender"`
}
func (u User) GetName() string {
return u.UserName
}
func (u *User) GetAge() int {
return u.Age
}
func main() {
var user = User{
UserName: "mszlu",
Age: 18,
Gender: "男",
}
//指针的方法不包含
//typeUser := reflect.TypeOf(user)
//methodNum := typeUser.NumMethod()
//for i := 0; i < methodNum; i++ {
// method := typeUser.Method(i)
// fmt.Printf("method name:%s ,type:%s, exported:%t\n", method.Name, method.Type, method.IsExported())
//}
//指针或者值的方法都包含
typeUserPoint := reflect.TypeOf(&user)
methodNumPoint := typeUserPoint.NumMethod()
for i := 0; i < methodNumPoint; i++ {
method := typeUserPoint.Method(i)
fmt.Printf("method name:%s ,type:%s, exported:%t\n", method.Name, method.Type, method.IsExported())
}
}
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
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
5.1.3 获取函数的信息
package main
import (
"fmt"
"reflect"
)
type User struct {
}
func (*User) Add(a, b int) string {
return fmt.Sprintf("%d", a+b)
}
func main() {
u := &User{}
typeAdd := reflect.TypeOf(u.Add)
fmt.Printf("func kind is %s \n", typeAdd.Kind())
in := typeAdd.NumIn() //输入参数的个数
out := typeAdd.NumOut() //输出参数的个数
for i := 0; i < in; i++ {
argType := typeAdd.In(i)
fmt.Printf("第%d个输入参数的类型:%s \n", i, argType)
}
for i := 0; i < out; i++ {
argType := typeAdd.Out(i)
fmt.Printf("第%d个输出参数的类型:%s \n", i, argType)
}
}
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
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
5.1.4 是否实现了接口
package main
import (
"fmt"
"reflect"
)
type People interface {
Color() string
}
type User struct {
}
func (*User) Color() string {
return "yellow"
}
type Dog struct {
}
func main() {
//我们想要知道Dog和User哪个实现了People接口呢?
//先获取接口类型 这原理是把nil强制转换为了*People
peopleType := reflect.TypeOf((*People)(nil)).Elem()
fmt.Println("people is interface? ", peopleType.Kind() == reflect.Interface)
valueUserType := reflect.TypeOf(User{})
pointUserType := reflect.TypeOf(&User{})
valueDogType := reflect.TypeOf(Dog{})
pointDogType := reflect.TypeOf(&Dog{})
fmt.Println("value user 是否实现people接口:", valueUserType.Implements(peopleType))
fmt.Println("point user 是否实现people接口:", pointUserType.Implements(peopleType))
fmt.Println("value dog 是否实现people接口:", valueDogType.Implements(peopleType))
fmt.Println("point dog 是否实现people接口:", pointDogType.Implements(peopleType))
}
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
6. reflect.Value
value就是用来做获取值,修改值等关于值的操作的。
比如:
type User struct {
Name string
}
func main() {
u := User{Name: "mszlu"}
//现在我们想要获取Name的值 mszlu 这时候就应该使用value去获取
valueOfUser := reflect.ValueOf(u)
fmt.Println("Name is ", valueOfUser.FieldByName("Name"))
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
6.1 转Type
type User struct {
Name string
}
func main() {
u := User{Name: "mszlu"}
//现在我们想要获取Name的值 mszlu 这时候就应该使用value去获取
valueOfUser := reflect.ValueOf(u)
typeOfUser := valueOfUser.Type()
name, _ := typeOfUser.FieldByName("Name")
fmt.Println("Name is ", valueOfUser.FieldByName("Name"))
fmt.Println("Name type is ", name.Type)
}
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
6.2 指针Value互转
type User struct {
Name string
}
func main() {
u := User{Name: "mszlu"}
//指针value 转 非指针value
point := reflect.ValueOf(&u)
noPoint := point.Elem()
fmt.Printf("point type: %s, noPoint type: %s \n", point.Type(), noPoint.Type())
fmt.Printf("point kind: %s, noPoint kind: %s \n", point.Kind(), noPoint.Kind())
//非指针转指针
newPoint := noPoint.Addr()
fmt.Printf("newPoint type: %s, newPoint kind: %s \n", newPoint.Type(), newPoint.Kind())
}
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
6.3 获取原始类型
type User struct {
Name string
}
func main() {
u := User{Name: "mszlu"}
//现在需要从value获取到user
v := reflect.ValueOf(u)
newUser := v.Interface().(User)
fmt.Println(newUser.Name)
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
6.4 空value判断
type User struct {
Name string
}
func main() {
var i interface{} //接口没有指向具体的值
v := reflect.ValueOf(i)
fmt.Printf("v持有值 %t, type of v is Invalid %t\n", v.IsValid(), v.Kind() == reflect.Invalid)
var user *User = nil
v = reflect.ValueOf(user) //Value指向一个nil
if v.IsValid() {
fmt.Printf("v持有的值是nil %t\n", v.IsNil()) //调用IsNil()前先确保IsValid(),否则会panic
}
var u User //只声明,里面的值都是0值
v = reflect.ValueOf(u)
if v.IsValid() {
fmt.Printf("v持有的值是对应类型的0值 %t\n", v.IsZero()) //调用IsZero()前先确保IsValid(),否则会panic
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
6.5 修改值
type User struct {
Name string
age int
}
func main() {
var user = User{
Name: "mszlu",
}
//注意: 修改值 比如传指针
valueOf := reflect.ValueOf(&user)
valueOf.Elem().FieldByName("Name").SetString("new mszlu")
fmt.Println(user.Name)
ageValue := valueOf.Elem().FieldByName("age")
if ageValue.CanSet() {
ageValue.SetInt(18)
} else {
fmt.Println("私有成员不能修改值")
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
6.6 调用方法
type User struct {
Name string
age int
}
func (u *User) GetName() string {
return u.Name
}
func main() {
var user = User{
Name: "mszlu",
}
//注意:调用方法时,使用指针,可以调用指针类型的方法和非指针类型的方法
valueOf := reflect.ValueOf(&user)
methodByName := valueOf.MethodByName("GetName")
//无参数传空切片
result := methodByName.Call([]reflect.Value{})
fmt.Println(result[0].Interface().(string))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
7. 其他
7.1 创建
type User struct {
Name string
age int
}
func (u *User) GetName() string {
return u.Name
}
func main() {
//创建struct
userType := reflect.TypeOf(User{})
valueUser := reflect.New(userType) //这里new出来的是指针 相当于reflect.ValueOf(&User{})
valueUser.Elem().FieldByName("Name").SetString("mszlu")
fmt.Println(valueUser)
//创建切片
userSliceType := reflect.TypeOf([]User{})
userSliceValue := reflect.MakeSlice(userSliceType, 1, 3)
userSliceValue.Index(0).Set(reflect.ValueOf(User{Name: "mszlu"}))
users := userSliceValue.Interface().([]User)
fmt.Println(users[0].Name)
//其他还有MakeMap,MakeChan,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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
7.2 修改slice
type User struct {
Name string
age int
}
func (u *User) GetName() string {
return u.Name
}
func main() {
//创建切片
users := make([]*User, 1, 3)
users[0] = &User{
Name: "mszlu",
}
//修改切片 必须使用指针
userSliceValue := reflect.ValueOf(&users)
//我们可以改变切片的长度
//userSliceValue.Elem().Index(1).Set(reflect.ValueOf(&User{Name: "mszlu"})) //会报错 slice index out of range
userSliceValue.Elem().SetLen(2)
userSliceValue.Elem().Index(1).Set(reflect.ValueOf(&User{Name: "mszlu1"}))
fmt.Println(users[1].Name)
//也可以直接Append
userSliceValue = reflect.Append(userSliceValue.Elem(), reflect.ValueOf(&User{Name: "mszlu2"}))
users = userSliceValue.Interface().([]*User)
fmt.Println(users[2].Name)
}
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
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