在实际的项目中,我们接收一个struct,要判断struct内部的字段、值、类型,reflect的数据结构体由
reflect.Type和reflect.Value两部分组成,并且reflect包提供了reflect.TypeOf和reflect.ValueOf两个函数来获取任意对象的Value和Type。
reflect.TypeOf()方法
任意值通过reflect.TypeOf()获得反射对象信息后,如果它的类型是结构体,可以通过反射值对象(reflect.Type)的NumField()和Field()方法获得结构体成员的详细信息。
eg:NumField()和Field()
typ:=reflect.TypeOf(x)
v:=reflect.ValueOf(x)
for i:=0;i<v.Elem().NumField();i++{
field := typ.Elem().Field(i) //字段的数据类型
fmt.Printf("&&&& typeof 反射:%v\n",field)
fmt.Printf("&&&& typeof 反射:%v\n",field.Name)
value := v.Elem().Field(i) //字段的数据值
&&&& typeof 反射:{Name string json:"name" 0 [0] false}
&&&& typeof 反射:{Age int json:"age" 16 [1] false}
&&&& typeof 反射:Name
&&&& typeof 反射:Age
这样通过对NumField()循环就可以拿到struct内部的字段名字field.Name
reflect.ValueOf()方法
reflect.ValueOf()返回的是reflect.Value类型,其中包含了原始值的值信息。reflect.Value与原始值之间可以互相转换。
reflect.Value类型提供的获取原始值的方法如下:
eg:
func reflectValue(x interface{}) {
v := reflect.ValueOf(x)
k := v.Kind()
switch k {
case reflect.Int64:
// v.Int()从反射中获取整型的原始值,然后通过int64()强制类型转换
fmt.Printf("type is int64, value is %d\n", int64(v.Int()))
case reflect.Float32:
// v.Float()从反射中获取浮点型的原始值,然后通过float32()强制类型转换
fmt.Printf("type is float32, value is %f\n", float32(v.Float()))
case reflect.Float64:
// v.Float()从反射中获取浮点型的原始值,然后通过float64()强制类型转换
fmt.Printf("type is float64, value is %f\n", float64(v.Float()))
}
}
func main() {
var a float32 = 3.14
var b int64 = 100
reflectValue(a) // type is float32, value is 3.140000
reflectValue(b) // type is int64, value is 100
// 将int类型的原始值转换为reflect.Value类型
c := reflect.ValueOf(10)
fmt.Printf("type c :%T\n", c) // type c :reflect.Value
}
E
l
e
m
(
)
方
法
在
传
指
针
的
时
候
可
以
获
取
到
指
针
的
值
\color{#A0A}{Elem()方法在传指针的时候可以获取到指针的值}
Elem()方法在传指针的时候可以获取到指针的值
\color{#A0A}{}
type struct1 struct{
Name string `json:"name"`
Age int `json:"age"`
}
func get_value(x interface{}){
传参是穿指针
typ:=reflect.TypeOf(x)
v:=reflect.ValueOf(x)
for i:=0;i<v.Elem().NumField();i++{
field := typ.Elem().Field(i) //字段的数据类型
value := v.Elem().Field(i) //字段的数据值
switch value.Kind() {
case reflect.String:
fmt.Printf("反射出来的key是 %v ,反射出来的值是:%v 类型是:%v\n",field.Name,value.String(),value.Kind())
value.SetString("charlie & bennie")
fmt.Printf("反射出来的key是 %v ,反射出来的值是:%v 类型是:%v\n",field.Name,value.String(),value.Kind())
case reflect.Int:
fmt.Printf("反射出来的key是 %v ,反射出来的值是:%v 类型是:%v\n",field.Name,value,value.Kind())
value.SetInt(88)
fmt.Printf("反射出来的key是 %v ,反射出来的值是:%v 类型是:%v\n",field.Name,value,value.Kind())
default:
fmt.Printf("useless type!\n")
}
}
}
func main(){
var mystruct1 struct1
mystruct1.Name="charlie"
mystruct1.Age=23
一定要传地址
一定要传地址
一定要传地址
get_value(&mystruct1)
反射出来的key是 Name ,反射出来的值是:bennie 类型名字是:string
反射出来的key是 Name ,反射出来的值是:charlie & bennie 类型名字是:string
{Age int json:"age" 16 [1] false} 23
反射出来的key是 Age ,反射出来的值是:23 类型名字是:int
反射出来的key是 Age ,反射出来的值是:88 类型名字是:int
package test
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
Gender string//所有field首字母都要大写,否则反射时会报错
}
func (p Person)Refpersion() reflect.Value{
t := reflect.TypeOf(p)
v := reflect.ValueOf(p)
fmt.Println(t, v) //main.Person {John 30 male}
return v
}
func Myreftest(){
reftest()
p := Person{"John", 30, "male"}
p.Refpersion()
p.struceelem()
p.Structmethod()
DoFiledAndMethod(p)
}
如果知道类型可以强制转换,interfacce().(type)
func reftest() {
var num int = 100
t := reflect.TypeOf(num)
v := reflect.ValueOf(&num)
ptr := reflect.ValueOf(&num)
fmt.Println(t.Name())//int
fmt.Println(t, v,ptr) //int 0xc420090030 0xc420090030
atype := v.Interface().(*int)//如果知道类型可以强制转换
fmt.Println(*atype) //100
}
func (p *Person)struceelem(){
v := reflect.ValueOf(p).Elem()
//p(v)的属性数量
count := v.NumField()
for i := 0; i < count; i++ {
fmt.Println(v.Type().Field(i).Name) //属性名
fmt.Println(v.Field(i).Type()) //属性类型
fmt.Println(v.Field(i)) //属性值
}
// 打印结果:
// Name string John
// Age int 99
// gender string male
//修改第一个属性的值
v.Field(0).SetString("Jane")
//修改Age属性的值
v.FieldByName("Age").SetInt(88)
fmt.Println(v) //{Jane 88 male}
fmt.Println(p) //{Jane 88 male}
}
func (p Person)Structmethod(){
v := reflect.ValueOf(&p).Elem()
//方法数量
count := v.NumMethod()
for i := 0; i < count; i++ {//只有方法传值和首字母大写的可以能反射
fmt.Println(v.Type().Method(i).Name, v.Method(i).Type())
}
params := make([]reflect.Value, 0)
v.Method(0).Call(params) //调用SetAge方法
fmt.Printf("call: %s",v) //&{John 50}
fmt.Println(p) //&{John 50}
res := v.MethodByName("Refpersion").Call(nil)
fmt.Println(&res) //Name:John, Age:50
}
func DoFiledAndMethod(input interface{}) {
getType := reflect.TypeOf(input)
fmt.Println("get Type is :", getType.Name())
getValue := reflect.ValueOf(input)
fmt.Println("88 get all Fields is:", getValue)
// 获取interface{}字段
// 1. 先获取interface的reflect.Type,然后通过NumField进行遍历
// 2. 再通过reflect.Type的Field获取其Field
// 3. 最后通过Field的Interface()得到对应的value
for i := 0; i < getType.NumField(); i++ {//NumField()返回结构体的field的count,即有几个字段,然后循坏获取type和value
field := getType.Field(i)
value := getValue.Field(i).Interface()
fmt.Printf("97 %s: %v = %v\n", field.Name, field.Type, value)
}
// 获取方法
// 1. 先获取interface的reflect.Type,然后通过.NumMethod进行遍历
for i := 0; i < getType.NumMethod(); i++ {
m := getType.Method(i)
fmt.Printf("104 %s: %v\n", m.Name, m.Type)
params := make([]reflect.Value, 0)
getValue.Method(i).Call(params)
}
}