首先来了解一下使用反射的好处:
-- 反射可大大提高程序的灵活性,使得interface{}有更大的发挥余地
--反射使用TypeOf()和ValueOf(函数从接口中获取目标对象的信息)
-- 反射会将匿名字段作为独立字段(匿名字段本质)
--想要利用反射修改对象的状态,前提是interface.data是settable,即pointer-interface
--通过反射可以动态地调用方法
然后让我们用一段代码,了解一下:
package main import ( "fmt" "reflect" ) type User struct { Id int Name string Age int } func (u User) ReflectCalL(name string ,age int){ fmt.Println(name,age,u.Name) } func (u User) ReflectCallno(){ fmt.Println("hello,world") } func main() { //reflect的基本功能TypeOf和ValueOf var num float64 = 1.2345 fmt.Println("type=",reflect.TypeOf(num)) // TypeOf用来动态获取输入参数接口中的值的类型,如果接口为空则返回nil fmt.Println("value=",reflect.ValueOf(num)) //ValueOf用来获取输入参数接口中的数据的值,如果接口为空则返回0 //从relfect.Value中获取接口interface的信息 //已知原有类型【进行“强制转换”】 realValue := value.Interface().(已知的类型) pointer := reflect.ValueOf(&num) //传递一个地址 value :=reflect.ValueOf(num) //传递一个值 converpointer:=pointer.Interface().(*float64) convervalue := value.Interface().(float64) fmt.Println(converpointer) fmt.Println(convervalue) u:=User{1,"joy",13} //未知原有类型【遍历探测其Filed】 info(u) //通过reflect.Value设置实际变量的值 newValue :=pointer.Elem() newValue.SetFloat(2.3456) fmt.Println("newValue=",num) //通过reflect.ValueOf来进行方法的调用 getValue :=reflect.ValueOf(u) //要通过反射来调用起对应的方法,必须要先通过reflect.ValueOf(interface)来获取到reflect.Value,得到“反射类型对象”后才能做下一步处理 method:=getValue.MethodByName("ReflectCalL") //指定准确方法的名字,否则会panic args :=[]reflect.Value{reflect.ValueOf("cc"),reflect.ValueOf(34)} //准备需要的参数切片 method.Call(args) 传参调用方法 //调用没有参数的方法 method1:=getValue.MethodByName("ReflectCallno") args1:=make([]reflect.Value,0) method1.Call(args1) } func info(o interface{}){ //接受一个空接口,任何一个结构体都可以看成一个空接口 t :=reflect.TypeOf(o) //先获取接口的reflect.Type fmt.Println(t) fmt.Println("Type:",t.Name()) v :=reflect.ValueOf(o) //获取接口中所有的值 fmt.Println(v) fmt.Println("Fileds") for i:=0;i<t.NumField();i++{ 通过NumFiled()获得字段的个数 f :=t.Field(i) val :=v.Field(i).Interface() 使用Interface()得到对应的值 fmt.Printf("%6s: %v = %v\n",f.Name,f.Type,val) } for i:=0;i<t.NumMethod();i++{ //获得所有方法的数目 m:=t.Method(i) fmt.Printf("%6s: %v\n",m.Name,m.Type) //方法名和类型 } 结果: 说明:
- 转换的时候,如果转换的类型不完全符合,则直接panic,类型要求非常严格!
- 转换的时候,要区分是指针还是值
- 也就是说反射可以将“反射类型对象”再重新转换为“接口类型变量”
总结:今天刚看到反射这个概念的时候,感觉有点懵,后来把所有代码都打了一遍,把一部分都输出了解之后,才感觉懂了许多,所以还是要多加练习,熟能生巧嘛