目录:
[显示]
反射的机制是在运行时动态调用对象的方法和属性
interface 和 反射
- 变量包括 (type,value) 两部分,所以 nil!=nil
- type包括 static type 和 concrete type (runtime系统看见的类型)
- 类型断言能否成功,取决于concrete type
只有interface类型,才有反射一说 一个interface{}类型的变量包含2个指针,一个指向值的类型,一个指向实际的值
reflect的基本功能 TypeOf 和 ValueOf
TypeOf获取数据的类型,若为空则返回nil
ValueOf获取数据的值,若接口为空则返回0
反射可以将 接口类型对象 转换为 反射类型对象(reflect.Type,reflect.Value)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package main import ( "fmt" "reflect" ) func main() { var num float64 = 1.2345 pointer := reflect.ValueOf(&num) value := reflect.ValueOf(num) // 强转时类型必须正确 否则会panic // 注意*float64与float64的区别 convertPointer := pointer.Interface().(*float64) convertValue := value.Interface().(float64) fmt.Println(convertPointer) // 0xc000064090 fmt.Println(convertValue) // 1.2345 } |
从reflect.Value获取接口interface信息
已知原有类型(进行强制转换)
realValue:=value.Interface().(已知类型)
反射可以将 反射类型对象 转换为 接口类型对象
注意:强转时类型必须正确 否则会panic
未知原有类型(遍历探测Field)
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 |
package main import ( "fmt" "reflect" ) type User struct { Id int Name string Age int } func (u User) ReflectCallFunc() { fmt.Println("Called ReflectCallFunc") } func DoFiledAndMethod(input interface{}) { getType := reflect.TypeOf(input) fmt.Println("Type is:", getType) getValue := reflect.ValueOf(input) fmt.Println("Value is:", getValue) //获取字段信息: //1.先获取interface的reflect.Type,而后通过NumField进行遍历 //2.通过reflect.Type的Field获取其Field //3.通过Field的Interface()得到对应的value for i := 0; i < getType.NumField(); i++ { filed := getType.Field(i) value := getValue.Field(i).Interface() fmt.Printf("%s:%v = %v\n", filed.Name, filed.Type, value) } //获取方法信息: //获取interface的reflect.Type,然后通过NumMethod进行遍历 for i := 0; i < getType.NumMethod(); i++ { method := getType.Method(i) fmt.Printf("%s:%v\n", method.Name, method.Type) } } func main() { user := User{1, "Allen", 25} DoFiledAndMethod(user) } |
通过reflect.Value设置实际变量的值
reflect.Value(X),只有当X是指针时,才可以修改实际变量X的值
Elem表示获取原始值对应的反射对象,所以原始值一定要传指针,否则会panic
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
package main import ( "fmt" "reflect" ) func main() { var num float64 = 1.2345 pointer := reflect.ValueOf(&num) newValue := pointer.Elem() //Elem,获取指针指向的值,相当于 *pointer fmt.Println(newValue.Type(), newValue.CanSet()) //重新赋值 newValue.SetFloat(3.14) fmt.Println(num) } |
通过reflect.ValueOf进行方法调用
先将方法注册,即MethodByName,然后通过Call调用
一定要指定参数为正确的方法名
MethodByName必须指定准确真实的方法名,否则会panic
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 |
package main import ( "fmt" "reflect" ) type User struct { Id int Name string Age int } func (u User) FuncWithArgs(name string, age int) { fmt.Println("Call FuncWithAgrs:", name, age) } func (u User) FuncWithoutArgs() { fmt.Println("Call FuncWithoutArgs") } func main() { user := User{1, "Allen", 25} getValue := reflect.ValueOf(user) //带参数的调用 methodValue := getValue.MethodByName("FuncWithArgs") args := []reflect.Value{reflect.ValueOf("testname"), reflect.ValueOf(30)} methodValue.Call(args) //无参函数的调用 methodValue = getValue.MethodByName("FuncWithoutArgs") args = make([]reflect.Value, 0) methodValue.Call(args) } |
reflect的性能
reflect的性能
反射会比较慢
涉及到内存分配及后续GC
reflect实现里有大量枚举(for循环)
参考文档:https://juejin.im/post/5a75a4fb5188257a82110544#heading-13
转载请注明:轻风博客 » golang的反射reflect