reflect 反射
反射:可以在运行时动态获取变量的相关信息
导入 reflect 包
reflect 包下主要是Type和Value 两个struct,
- Type封装了“类型”的属性,定义相关的东西找他;
- Value主要封装了“值”的属性,与值相关的东西找他没错。此外,他是线程安全的(或者叫goroutine安全)
reflect包下主要有两个函数:
-
func TypeOf(i interface{}) Type获取变量的类型,返回reflect.Type类型
-
func ValueOf(i interface{}) Value获取变量的值,返回reflect.Value类型
1. reflect.Value.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
)
3.reflect.TypeOf
package main import ( "fmt" "reflect" ) func GetType(){ var i int typeInfo := reflect.TypeOf(i) fmt.Printf("%#v",typeInfo) /*输出内容是: &reflect.rtype{size:0x8, ptrdata:0x0, hash:0xf75371fa, tflag:0x7, align:0x8, fieldAlign:0x8, kind:0x82, alg:(*reflect.typeAlg)(0x53ca50), gcdata:(*uint8)(0x4d8d90), str:1019, ptrToThis:44736}} rtype结构体 type rtype struct { size uintptr ptrdata uintptr // number of bytes in the type that can contain pointers hash uint32 // hash of type; avoids computation in hash tables tflag tflag // extra type information flags align uint8 // alignment of variable with this type fieldAlign uint8 // alignment of struct field with this type kind uint8 // enumeration for C alg *typeAlg // algorithm table gcdata *byte // garbage collection data str nameOff // string form ptrToThis typeOff // type for pointer to this type, may be zero } */ } func main(){ GetType() }
4.获取变量的类型
package main import ( "fmt" "reflect" ) func GetType(a interface{}){ //获取变量类型 typeInfo := reflect.TypeOf(a) kindof := typeInfo.Kind() fmt.Printf("%v\n",kindof) } type Student struct{ Name string Age int } func main(){ var i int var s Student var c []string var a [10]int var p *int GetType(i) //int GetType(s) //struct GetType(c) //slice GetType(a) //array GetType(p) //ptr }
5.Type 类型的方法
package main import ( "fmt" "reflect" ) func GetType(a interface{}){ //获取变量类型 typeInfo := reflect.TypeOf(a) kindof := typeInfo.Kind() fmt.Printf("%v\n",kindof) } func GetNmuberMethod(a interface{}){ typeInfo := reflect.TypeOf(a) num_of_method := typeInfo.NumMethod() fmt.Println(num_of_method) } type Student struct{ Name string Age int } func(s *Student) SetName(name string){ //方法一 s.Name = name } func(s *Student) SetAge(age int){ //方法二 s.Age = age } func GetMethod(a interface{}){ typeInfo := reflect.TypeOf(a) methodname,ok:= typeInfo.MethodByName("SetName") if !ok { fmt.Println("have no method name") }else{ fmt.Println(methodname) } } func main(){ var s Student GetNmuberMethod(&s) //2 ,获取s的方法 GetMethod(&s) //typeInfo := reflect.TypeOf(a) }
6.reflect.Value.Interface(),转换成interface{}类型
变量 <------------>interface{}<------------------------->reflect.Value
func GetValue(){ var i int =100 valueinfo := reflect.ValueOf(i) //变量i 转成Value类开 tmp := valueinfo.Interface() //value类型转成接口 val := tmp.(int) //接口转成int fmt.Println(val)
fmt.Println(valueinfo.Int()) //获取value类型的值。 } func main(){ GetValue() //100 }
valueinfo.Type() 类型比如 Student
valueinfo.Kind() 静态类型,struct
7.利用反射来获取变量的值
reflect.ValueOf(x).Float()
reflect.ValueOf(x).Int()
reflect.ValueOf(x).String()
reflect.ValueOf(x).Bool()
8.通过反射来改变变量的值
reflect.Value.SetXX相关⽅法,⽐如:
reflect.Value.SetFloat(),设置浮点数
reflect.Value.SetInt(),设置整数
reflect.Value.SetString(),设置字符串
func main(){ var a float64 // v :=reflect.ValueOf(a) //这是一个值类型拷贝,修改不生效 panic: reflect: reflect.Value.SetFloat using unaddressable value v :=reflect.ValueOf(&a) //传入a的地址 // v.SetFloat(3.3)//引用类型赋值不能直接这样赋值 指针 赋值 :*地址=value panic: reflect: reflect.Value.SetFloat using unaddressable value v.Elem().SetFloat(3.3) //反射中指针赋值 fmt.Printf("%v\n",a)//3.3
其中v.Elem()⽤来获取指针指向的变量,相当于:
var a *int;
*a = 100
9.⽤反射操作结构体
a. reflect.Value.NumField()获取结构体中字段的个数
b. reflect.Value.Method(n).Call来调⽤结构体中的⽅法
获取个数:
package main import ( "fmt" "reflect" ) type Student struct{ Name string Age int Sex int } func(s *Student) Set(name string,age,sex int){ s.Name = name s.Age = age s.Sex = sex } func(s *Student) Getname(name string){ s.Name = name } func TestStruct(){ var s *Student = &Student{} s.Set("www",18,1) v := reflect.ValueOf(s) num := v.Elem().NumField() //指针变量的字段数量 fmt.Println(num) //3 sexinfo := v.Elem().FieldByName("Sex") //获取字段信息 fmt.Println(sexinfo) //1 sexinfo.SetInt(100) fmt.Println(s) //&{www 18 100} } func main(){ TestStruct() //3 }
调用结构体方法:
type Student struct{ Name string Age int Sex int } func(s *Student) Set(name string,age,sex int){ s.Name = name s.Age = age s.Sex = sex } func(s *Student) Getname(name string){ s.Name = name } func TestStruct_value(){ var s *Student = &Student{} v := reflect.ValueOf(s) setinfo := v.MethodByName("Set") var par []reflect.Value name := "wanghj" age := 18 sex := 1 par = append(par,reflect.ValueOf(name)) par = append(par,reflect.ValueOf(age)) par = append(par,reflect.ValueOf(sex)) setinfo.Call(par) fmt.Printf("%v\n",s) }