Reflect
reflect包实现了运行时反射,允许程序操作任意类型的对象。典型用法是用静态类型interface{}保存一个值,通过调用TypeOf获取其动态类型信息,该函数返回一个Type类型值。调用ValueOf函数返回一个Value类型值,该值代表运行时的数据。Zero接受一个Type类型参数并返回一个代表该类型零值的Value类型值。
1. reflect.TypeOf()
-
info := reflect.TypeOf() :获取任意值的类型对象
-
info.Name():类型名称 表类型 比如type MyFloat64 float64中的MyFloat64 ,或者type T struct 中的T;对于未定义的类型返回空字符串
-
// 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
-
-
info.Kind():种类 基类型 比如type MyFloat64 float64中的float64;或者type T struct 中的struct
-
// Kind returns the specific kind of this type. Kind() Kind
-
-
eg: func reflect_type(a interface{}) { t := reflect.TypeOf(a) fmt.Println("Type:", t) n := t.Name() fmt.Println("Type Name:", n) //kind ()可以获取具体类型 k := t.Kind() fmt.Println("Kind:", k) switch k { case reflect.Float64: fmt.Println("a :", reflect.Float64) case reflect.String: fmt.Println("a :", reflect.String) case reflect.Ptr: fmt.Println("a :", reflect.Ptr) default: fmt.Println("kind illegal") } } type MyFloat64 float64 type People struct { } func main() { var a MyFloat64 = 3.14 reflect_type(a) var zhangsan People = People{} reflect_type(zhangsan) } //结果: Type: main.MyFloat64 Type Name: MyFloat64 Kind: float64 a : float64 Type: main.People Type Name: People Kind: struct a : struct
2. reflect.ValueOf()
-
v :=reflect.ValueOf() :获取原始值的值信息
-
kind := v.Kind():种类 基类型 比如type MyFloat64 float64中的float64;或者type T struct 中的struct
-
v.Int(): 原始值 类型必须对应才能取到原值,所以通常会先判断kind
-
通过反射设置变量的值:
- 先通过v:=reflect.ValueOf(a)取到原值信息
- 然后通过 v.Elem().Kind()判断类型
- 最后通过v.Elem().SetFloat(7.9)修改原值
- 注意:修改反射值时的a参数必须是原值的指针或地址;否则报错:panic: reflect: reflect.Value.SetFloat using unaddressable value
-
func reflect_set_value(a interface{}) { v := reflect.ValueOf(a) k := v.Kind() switch k { case reflect.Float64: v.SetFloat(6.9) fmt.Println("a is:", v.Float()) case reflect.Ptr: v.Elem().SetFloat(7.9) fmt.Println("case:", v.Elem().Float()) //地址 fmt.Println("addr:", unsafe.Pointer(v.Pointer())) } } func main() { var a MyFloat64 = 3.14 reflect_set_value(&a) fmt.Println("main a:", a) fmt.Println("main &a:", &a) } //结果 case: 7.9 addr: 0xc000014088 main a: 7.9 main &a: 0xc000014088
3. 结构体反射
-
reflect.TypeOf()获得反射对象信息后,如果它的类型是结构体,可以通过反射值对象(reflect.TypeOf)的 NumField()和 Field()方法获得结构体成员的详细信息
-
t := reflect.TypeOf(u)
-
t.NumField():获取结构体字段个数
-
f:=t.Field(0) :获取结构体第一个字段
- f.Name:字段名
- f.Type:字段类型
- f.Tag:字段标签
-
f:=t.FieldByName(“Age”):获取对应字段Age的信息
- f.Name:字段名
- f.Type:字段类型
- f.Tag:字段标签
-
t.NumMetod():获取方法个数
-
f:=t.Method(0):和结构体的方法声明顺序没有关系,和结构体方法名的ASCII有关系
- f.Name:方法名
- f.Type:方法类型
-
f:=t.MethodByName(“HelloA”):获取结构体指定方法信息;未找到对应方法返回零值(reflect.Value{}) 。
-
// MethodByName returns a function value corresponding to the method // of v with the given name. // The arguments to a Call on the returned function should not include // a receiver; the returned function will always use v as the receiver. // It returns the zero Value if no method was found. func (v Value) MethodByName(name string) Value
-
f.Name:方法名
-
f.Type:方法类型
-
f.Func.Call(v):调用方法;
- Call(v):v为参数切片,类型[]reflect.Value,例如:[]reflect.Value{reflect.ValueOf(1), reflect.ValueOf(“s1”)
- 通过TypeOf反射对象调用方法时,v的list中,第一个参数必须是接收器类型的实例[]reflect.Value{reflect.ValueOf(User{}), reflect.ValueOf(1), reflect.ValueOf(“s1”)}
-
-
-
t:=reflect.ValueOf(u)
- t.MethodByName(“HelloA”).Call(v):调用HelloA方法
- t.Method(0).Call(v):执行方法,和结构体的方法顺序没有关系,和结构体方法的ASCII有关系
- Call(v):v为参数切片,类型[]reflect.Value,例如:[]reflect.Value{reflect.ValueOf(1), reflect.ValueOf(“s1”)
- 注意 通过ValueOf反射出的对象调用 方法时,v的参数列表第一个元素是对应方法的参数,而不是接收器实例
//结构体反射
func (u User) HelloB(v int, s string) {
fmt.Println("Hello B: int:", v, "string:", s)
}
func (u User) HelloA() {
fmt.Println("Hello A")
}
func reflect_fun(a interface{}) {
t := reflect.TypeOf(a)
fmt.Println("Type:", t)
n := t.Name()
fmt.Println("Name:", n)
v := reflect.ValueOf(a)
fmt.Printf("%#v \n", v)
//t.NumField()取结构体字段个数
for i := 0; i < t.NumField(); i++ {
//取每个字段 Name Type Tag
f := t.Field(i)
fmt.Println("f(", i, "): Name:", f.Name, " Type:", f.Type, " Tag(json):", f.Tag.Get("json"), " Tag(db):", f.Tag.Get("db"))
//获取字段的值信息
//Interfance():获取字段对应的值
val := v.Field(i).Interface()
fmt.Println("val:", val)
}
fmt.Println("==========================遍历方法================================")
for i := 0; i < t.NumMethod(); i++ {
//方法的顺序与方法名的ASCII排序有关
m := t.Method(i)
fmt.Println("m(", i, ").Name:", m.Name, " Type:", m.Type)
}
fmt.Println("==========================取指定方法信息================================")
f, _ := t.MethodByName("HelloB")
fmt.Println("HelloB.Name:", f.Name, " Type:", f.Type)
f.Func.Call([]reflect.Value{reflect.ValueOf(User{}), reflect.ValueOf(1), reflect.ValueOf("s1")})
fmt.Println("==========================方法信息调用================================")
v.MethodByName("HelloA").Call(nil)
v.MethodByName("HelloB").Call([]reflect.Value{reflect.ValueOf(2), reflect.ValueOf("s2")})
reflect.ValueOf(User{}).MethodByName("HelloB").Call([]reflect.Value{reflect.ValueOf(3), reflect.ValueOf("s3")})
if v.MethodByName("HelloC") == (reflect.Value{}) {
fmt.Println("HelloC not found")
}
}
func main() {
u := User{
Id: 1,
Age: 20,
Name: "张三",
}
reflect_fun(u)
}
//结果
Type: main.User
Name: User
main.User{Id:1, Age:20, Name:"张三"}
f( 0 ): Name: Id Type: int Tag(json): id Tag(db): db1
val: 1
f( 1 ): Name: Age Type: int Tag(json): age Tag(db): db2
val: 20
f( 2 ): Name: Name Type: string Tag(json): name Tag(db):
val: 张三
==========================遍历方法================================
m( 0 ).Name: HelloA Type: func(main.User)
m( 1 ).Name: HelloB Type: func(main.User, int, string)
==========================取指定方法信息================================
HelloB.Name: HelloB Type: func(main.User, int, string)
Hello B: int: 1 string: s1
==========================方法信息调用================================
Hello A
Hello B: int: 2 string: s2
Hello B: int: 3 string: s3
HelloC not found