反射
反射是指在程序运行期对程序本身进行访问和修改的能力。
- 基于反射的代码是极其脆弱的,反射中的类型错误会在真正运行的时候才会引发panic,那很可能是在代码写完的很长时间之后。
- 大量使用反射的代码通常难以理解。
- 反射的性能低下,基于反射实现的代码通常比正常代码运行速度慢一到两个数量级。
-
反射基础
package main //接口值有特定类型和值组成,任意接口值在反射中都可以理解为由reflect.Type和reflect.Value两部分组成 import ( "fmt" "reflect" ) type cat struct { } // 利用reflect.type获取任意值的类型对象,从而访问类型信息 // 反射中类型分为Type和Kind,Type就是定义的类型,Kind是底层的类型,Kind用于区分指针、结构体 func reflectType(x interface{}) { v := reflect.TypeOf(x) fmt.Printf("type:%v\n", v) fmt.Printf("type name:%v,type kind:%v\n", v.Name(), v.Kind()) } // 利用reflect.value获取任意值 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 reflectSetValue1(x interface{}) { // v := reflect.ValueOf(x) // if v.Kind() == reflect.Int64 { // v.SetInt(200) //修改的是副本,reflect包会引发panic // } // } // 反射中修改值记住1.传递指针 2.使用Elem()方法获取值,这个方法类似于对指针使用* func reflectSetValue2(x interface{}) { v := reflect.ValueOf(x) // 反射中使用 Elem()方法获取指针对应的值 if v.Elem().Kind() == reflect.Int64 { v.Elem().SetInt(200) } } func main() { var a float32 = 3.14 reflectType(a) // type:float32 var b int64 = 100 reflectType(b) // type:int64 var c = cat{} reflectType(c) // 获取值 reflectValue(a) // 利用反射修改值,需要传入待修改数的指针 reflectSetValue2(&b) fmt.Println(b) // IsNil()用于判断指针是否为空 var d *int fmt.Println("var d *int Isnil:", reflect.ValueOf(d).IsNil()) // IsValid()用于判定返回值是否有效 e := struct{}{} fmt.Println("不存在的结构体成员", reflect.ValueOf(e).FieldByName("abc").IsValid()) // 尝试从map中查找一个不存在的键 // 注意在找类型时先把类型转换为reflect.value f := map[string]int{} fmt.Println("map中不存在的键:", reflect.ValueOf(f).MapIndex(reflect.ValueOf("卡卡")).IsValid()) } -
结构体反射
package main import ( "fmt" "reflect" ) type student struct { Name string `json:"name" kaka:"zq"` Score int `json:"score" kaka:"Morain"` } func main() { stu1 := student{ Name: "小王子", Score: 90, } t := reflect.TypeOf(stu1) fmt.Println(t.Name(), t.Kind()) // student struct // 通过for循环遍历结构体的所有字段信息 // 注意t是值类型,如果是指针类型的先用Elum()取值 for i := 0; i < t.NumField(); i++ { // 获取每一个字段 field := t.Field(i) fmt.Printf("name:%s index:%d type:%v json tag:%v\n", field.Name, field.Index, field.Type, field.Tag.Get("kaka")) } // 通过字段名获取指定结构体字段信息 if scoreField, ok := t.FieldByName("Score"); ok { fmt.Printf("name:%s index:%d type:%v json tag:%v\n", scoreField.Name, scoreField.Index, scoreField.Type, scoreField.Tag.Get("json")) } }
本文详细介绍了Go语言中的反射(reflection)概念,包括反射的基础知识、如何通过反射获取和修改变量的值,以及结构体反射。强调了反射的脆弱性、难以理解和低性能,并提供了相关代码示例来演示反射的使用方法。通过反射,可以在运行时检查和修改程序的内部结构,但过度使用可能带来维护困难和性能损失。
459

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



