【原创】go语言学习(十八)反射详解
目录
- 变量介绍
- 反射介绍
- 结构体反射
- 反射总结以及应用场景
变量介绍
1、变量的内在机制
A. 类型信息,这部分是元信息,是预先定义好的
B. 值类型,这部分是程序运行过程中,动态改变的
var arr [10]int arr[0] = 10 arr[1] = 20 arr[2] = 30 arr[3] = 40 arr[4] = 50 type Animal struct { Name string age int } var a Animal
反射介绍
1、 反射与空接口
A. 空接口可以存储任何类型的变量
B. 那么给你一个空接口,怎么里面存储的是什么东西?
C. 在运行时动态的获取一个变量的类型信息和值信息,就叫反射
2、怎么分析?
A. 内置包 reflect
B. 获取类型信息: reflect.TypeOf
C. 获取值信息: reflect.ValueOf
3、 基本数据类型分析?
package main import ( "fmt" "reflect" ) func main() { var x float64 = 3.4 fmt.Println("type:", reflect.TypeOf(x)) }
4、 Type.Kind(),获取变量的类型
package main import ( "fmt" "reflect" ) func main() { var x float64 = 3.4 t := reflect.TypeOf(x) fmt.Println("type:", t.Kind()) }
const ( Invalid Kind = iota Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Ptr Slice String Struct UnsafePointer )
5、 reflect.ValueOf,获取变量的值相关信息
var x float64 = 3.4 v := reflect.ValueOf(x) //和reflect.TypeOf功能是一样的 fmt.Println("type:", v.Type()) fmt.Println("kind is float64:", v.Kind() == reflect.Float64) fmt.Println("value:", v.Float())
6、 通过反射设置变量的值
var x float64 = 3.4 v := reflect.ValueOf(x) fmt.Println("type:", v.Type()) fmt.Println("kind is float64:", v.Kind() == reflect.Float64) v.SetFloat(6.8) fmt.Println("value:", v.Float())
7、通过反射设置变量的值
var x float64 = 3.4 //传地址进去,不传地址的话,改变的是副本的值 //所以在reflect包里直接崩溃了!!!!! v := reflect.ValueOf(&x) fmt.Println("type:", v.Type()) fmt.Println("kind is float64:", v.Kind() == reflect.Float64) v.SetFloat(6.8) fmt.Println("value:", v.Float())
8、通过反射设置变量的值
var x float64 = 3.4 //传地址进去,不传地址的话,改变的是副本的值 //所以在reflect包里直接崩溃了!!!!! v := reflect.ValueOf(&x) fmt.Println("type:", v.Type()) fmt.Println("kind is float64:", v.Kind() == reflect.Float64) //通过Elem()获取指针指向的变量,从而完成赋值操作。 //正常操作是通过*号来解决的,比如 //var *p int = new(int) //*p = 100 v.Elem().SetFloat(6.8) fmt.Println("value:", v.Float())
9、通过反射设置变量的值
var x float64 = 3.4 v := reflect.ValueOf(&x) fmt.Println("type:", v.Type()) fmt.Println("kind is float64:", v.Kind() == reflect.Float64) v.Elem().SetInt(100) fmt.Println("value:", v.Float())
结构体反射
1、获取结构体类型相关信息
package main import ( "fmt" "reflect" ) type S struct { A int B string } func main() { s := S{23, "skidoo"} v := reflect.ValueOf(s) t := v.Type() for i := 0; i < v.NumField(); i++ { f := v.Field(i) fmt.Printf("%d: %s %s = %v\n", i, t.Field(i).Name, f.Type(), f.Interface()) } }
2、 获取结构体类型相关信息
package main import ( "fmt" "reflect" ) type S struct { A int B string } func main() { s := S{23, "skidoo"} v := reflect.ValueOf(s) t := v.Type() for i := 0; i < v.NumField(); i++ { f := v.Field(i) fmt.Printf("%d: %s %s = %v\n", i, t.Field(i).Name, f.Type(), f.Interface()) } }
3、设置结构体相关字段的值
package main import ( "fmt" "reflect" ) type S struct { A int B string } func main() { s := S{23, "skidoo"} v := reflect.ValueOf(&s) t := v.Type() v.Elem().Field(0).SetInt(100) for i := 0; i < v.Elem().NumField(); i++ { f := v.Elem().Field(i) fmt.Printf("%d: %s %s = %v\n", i, t.Elem().Field(i).Name, f.Type(), f.Interface()) } }
4、 获取结构体的方法信息
package main import ( "fmt" "reflect" ) type S struct { A int B string } func (s *S) Test() { fmt.Println("this is a test") } func main() { s := S{23, "skidoo"} v := reflect.ValueOf(&s) t := v.Type() v.Elem().Field(0).SetInt(100) fmt.Println("method num:", v.NumMethod()) for i := 0; i < v.NumMethod(); i++ { f := t.Method(i) fmt.Printf("%d method, name:%v, type:%v\n", i, f.Name, f.Type) } }
5、调用结构体中的方法
package main import ( "fmt" "reflect" ) type S struct { A int B string } func (s *S) Test() { fmt.Println("this is a test") } func (s *S)SetA(a int) { s.A = a } func main() { s := S{23, "skidoo"} v := reflect.ValueOf(&s) m := v.MethodByName("Test") var args1 []reflect.Value m.Call(args1) setA := v.MethodByName("SetA") var args2 []reflect.Value args2 = append(args2, reflect.ValueOf(100)) setA.Call(args2) fmt.Printf("s:%#v\n", s) }
6、获取结构体中tag信息
package main import ( "fmt" "reflect" ) type S struct { F string `species:"gopher" color:"blue" json:"f"` } func main() { s := S{} st := reflect.TypeOf(s) field := st.Field(0) fmt.Println(field.Tag.Get("color"), field.Tag.Get("species"), field.Tag.Get("json")) }
反射总结以及应用场景
1、反射总结
A.在运行时动态的获取一个变量的类型信息和值信息
2. 应用场景
A. 序列化和反序列化,比如json, protobuf等各种数据协议
B. 各种数据库的ORM, 比如gorm,sqlx等数据库中间件
C. 配置文件解析相关的库, 比如yaml、ini等