更新系列
Go语言头秃之路(零)
Go语言头秃之路(一)
Go语言头秃之路(二)
Go语言头秃之路(三)
Go语言头秃之路(四)
Go语言头秃之路(五)
Go语言头秃之路(六)
-
反射
反射可以在运行时动态获取变量的各种信息- 应用场景:
- 当不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口,这时需要对函数或方法反射。
eg: func bridge(funcPtr interface{}, args …interface{})
第一个参数funcPtr以接口形式传入函数指针,函数参数args以可变参数的形式传入,bridge函数中可以用反射来动态执行funcPtr函数。 - 对结构体序列化时, 如果结构体有指定tag, 也会使用到反射生成对应的字符串。
reflect包实现了运行时反射,允许程序操作任意类型的对象。
常用方法:
reflect.TypeOf() 返回 reflect.Type类型
reflect.ValueOf() 返回 reflect.Value类型
具体使用:
func test(i interface{}) { // 1. interface{} -> reflect.Value类型 rVal := reflect.ValueOf(b) // 2. 将reflect.Value类型转回原来变量类型 // reflect.Value类型 -> interface{} iVal := rVal.Interface() // interface{} -> 原来的变量类型 (断言) v := iVal.(Person) }
- 需要想要修改反射对应变量值,需要reflect.ValueOf()接收地址,然后使用reflat.Value.Elem().Set…方法
i := 3 rVal := reflect.ValueOf(&i) fmt.Println(rVal.Kind()) // ptr // Elem() 相当于取出指针指向地址的值进行修改 fmt.Println(rVal.Elem().Int()) // 3 rVal.Elem().SetInt(6) fmt.Println(i) // 6- 修改struct反射中元素值的方法(需要传struct地址)
- 将反射转化为reflect.Value类型(reflect.ValueOf()),接着转为interface(reflect.Value.Interface()),然后通过断言获得原变量,最后进行赋值即可
- 使用Elem() + Field() + Set…(xx)方法
两种方法饭粒:func TestStruct2(i interface{}) { //获取reflect.Value 类型 val := reflect.ValueOf(i) // 方法1. // inter := val.Interface() // astruct := inter.(*Monster) // astruct.Name = "黄鼠狼" // 方法2. ele := val.Elem() ele.Field(0).SetInt(500) ele.Field(1).SetString("黄鼠狼") // fmt.Printf("%v, type: %T", ele, ele) }
- 一些小程序
- 反射应用1:定义两个函数test1和test2, 定义一个适配器函数用作统一处理接口
func TestReflectFunc(t *testing.T) { call1 := func(v1 int, v2 int) { t.Log(v1, v2) } call2 := func(v1 int, v2 int, s string) { t.Log(v1, v2, s) } var ( function reflect.Value inValue []reflect.Value n int ) bridge := func(call interface{}, args...interface{}) { n = len(args) inValue = make([]reflect.Value, n) for i := 0; i<n; i++ { inValue[i] = reflect.ValueOf(args[i]) } function = reflect.ValueOf(call) function.Call(inValue) } } - 反射应用2:使用反射操作任意结构体类型
type user struct { UserId string Name string } func TestReflectStruct(t *testing.T) { var ( model *user sv reflect.Value ) model = &user{} sv = reflect.ValueOf(model) t.Log("reflect.ValueOf", sv.kind().String()) sv = sv.Elem() t.Log("reflect.ValueOf.Elem", sv.Kind().string()) sv.FieldByName("UserId").SetString("333333") sv.FieldByName("Name").SetString("Fone") t.Log("model", model) } - 反射应用3:使用反射创建并操作结构体
func TestReflectStructPtr(t *testing.T) { var ( model *user st reflect.Type elem reflect.Value ) st = reflect.TypeOf(model) // 获取类型*user t.Log("reflect.TypeOf", st.Kind().string()) // ptr st = st.Elem() // st 指向的类型 t.Log("reflect.TypeOf.Elem", st.Kind().String()) // struct elem = reflect.New(st) // New返回一个Value类型值,该值持有一个指向类型为typ的新申请的零值的指针 t.Log("reflect.New", elem.Kind().string()) // ptr t.Log("reflect.New.Elem", elem.Elem().kind().String()) // struct // model 就是创建的user结构体变量(实例) model = elem.Interface().(*user) // model是*user, 它的指向和elem是一样的 elem = elem.Elem() // 取得elem指向的值 elem.FieldByName("UserId").SetString("007") // 赋值 elem.FieldByName("Name").SetString("Fone") // 赋值 t.Log("model model.Name", model, model.Name) }
- 一些注意事项
- reflect.ValueOf.Method(i int)
这里的方法排序是按照方法名(ascii码)首字母顺序。
1786

被折叠的 条评论
为什么被折叠?



