ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] ## 反射 ### 原始类型-->接口-->反射类型 ![](https://img.kancloud.cn/ad/c1/adc1daa9dc0ddaf21a416d0fa39027b2_1656x595.png) ### Kind 反射的类型种类 ``` type Users interface{ GetName() } type UsersPtr interface{ GetAge() GetSex() } type Person struct { Name string `json:"name" xml:"name1"` age int `json:"age"` gender int `json:"sex"` } func (p Person) GetName(){ fmt.Println("叫我小叮当啊") } func (p *Person) GetAge(){ fmt.Println(18) } func (p *Person) GetSex(){ fmt.Println(1) } person := reflect.TypeOf(Person{}) fmt.Println(person.Name())// Person pK := person .Kind() fmt.Println(pK) // struct ``` ### reflect.Type 用于获取任何表达式的类型 ``` //返回type类型的变量 func TypeOf(i interface{}) Type //Type 类型可调用的方法 type Type interface { // 该类型内存分配大小(内存对齐单位子节) Align() int // 该类型作为结构体字段时内存分配大小(内存对齐单位子节) FieldAlign() int // 根据index in [0, NumMethod())获取方法 Method(int) Method // 根据方法名获取方法 MethodByName(string) (Method, bool) // 获取所有可用方法数量 // 接口类型 获取包含未导出方法 NumMethod() int // 返回类型名,未定义则为空 Name() string // 返回类型所在包名,未定义则为空 PkgPath() string // 错误类型所需子节数 unsafe.Sizeof. Size() uintptr // 返回类型名称字符串 String() string // 返回此类型的kind类型 Kind() Kind // 返回是否实现了u接口 Implements(u Type) bool // 返回类型的值是否可分配给类型u AssignableTo(u Type) bool // 返回类型的值是否可以转换为u类型 ConvertibleTo(u Type) bool // 返回类型的值是否可对比 Comparable() bool // Methods applicable only to some types, depending on Kind. // The methods allowed for each kind are: // // Int*, Uint*, Float*, Complex*: Bits // Array: Elem, Len // Chan: ChanDir, Elem // Func: In, NumIn, Out, NumOut, IsVariadic. // Map: Key, Elem // Ptr: Elem // Slice: Elem // Struct: Field, FieldByIndex, FieldByName, FieldByNameFunc, NumField // Bits returns the size of the type in bits. // It panics if the type's Kind is not one of the // sized or unsized Int, Uint, Float, or Complex kinds. Bits() int // Elem返回类型的元素类型 // 不是 Array, Chan, Map, Ptr, or Slice. panic Elem() Type // --------------- struct ------------------------ // 字段返回结构类型的第i个字段。 // 不是struct 或者下表越界 painc Field(i int) StructField // 字段返回嵌套结构类型的第i个字段。 // 不是struct 或者下表越界 painc FieldByIndex(index []int) StructField // 按名称返回字段 FieldByName(name string) (StructField, bool) // 按过滤方法返回匹配字段 FieldByNameFunc(match func(string) bool) (StructField, bool) // 返回结构体字段总数 // 不是 Struct panic. NumField() int // --------------- struct ------------------------ // --------------- func -------------------- //返回函数类型第i的输入参数 // 不是Func painc In(i int) Type // 返回方法输入参数总数 // 不是Func painc NumIn() int // 返回函数输出参数总数 // 不是Func painc NumOut() int // 返回函数类型第i的输出参数 // 不是Func painc Out(i int) Type // 返回函数是否包含可变参数 // 不是Func painc IsVariadic() bool // --------------- func -------------------- // --------------- Map -------------------- // 返回map的key类型 // 不是Map panic Key() Type // --------------- Map -------------------- // --------------- Array -------------------- // 返回数组类型的长度 // 不是Array panic Len() int // --------------- Array -------------------- // --------------- chan -------------------- // 返回chan类型的方向,不是chan会panic ChanDir() ChanDir // --------------- chan -------------------- common() *rtype uncommon() *uncommonType } ``` #### 获取Type类型 ``` var x int tInt := reflect.TypeOf(x) fmt.Println(tInt) // int var name string tSring := reflect.TypeOf(name) fmt.Println(tSring) // string ``` #### 指针Type -->非指针Type ``` ptrType = reflect.TypeOf(&Person{}) tType = reflect.TypeOf(Person{}) //通过Elem fmt.Println(ptrType.Elem().Name(), tType.Name() ) // Person Person ``` #### 结构体成员变量 ``` type StructField struct { Name string // 字段名 PkgPath string // 字段路径 Type Type // 字段反射类型对象 Tag StructTag // 字段的结构体标签 Offset uintptr // 字段在结构体中的相对偏移 Index []int // Type.FieldByIndex中的返回的索引值 Anonymous bool // 是否为匿名字段 } //只能用struct的Type,不能是指针的Type person := reflect.TypeOf(Person{}) //获取字段数量,包括全部结构体字段, fieldNum := person.NumField() fmt.Println(fieldNum) for i:= 0;i< fieldNum;i++{ field:= person.Field(i)// 在这返回StructField 类型 fmt.Printf("字段名称:%s 偏移量: %d 是否匿名:%t 类型:%s 包外是否可见:%t allTag:%s jsonTag: %s\n", field.Name, field.Offect, field.Anonymous, field.Type, field.IsExported(), field.Tag, field.Tag.Get("json") ) } //可以通过FieldByName获取Field field,has := person.FieldByName("Name") fmt.Println(field,has) //{Name string json:"name" xml:"name1" 0 [0] false} true field,has = person.FieldByName("age") fmt.Println(field,has) //{age main int json:"age" 16 [1] false} true field,has = person.FieldByName("gender") fmt.Println(field,has) //{gender main int json:"sex" 24 [2] false} true //不存在的字段 field,has = person.FieldByName("gender1") fmt.Println(field,has) //{ <nil> 0 [] false} false ``` #### 结构体成员方法 ``` //结构体,只包含值的方法不包含指针的方法 person := reflect.TypeOf(&Person{}) //获取方法数量 methodNum := person.NumMethod() for i:=0;i<methodNum;i++{ method := person.Method(i) fmt.Printf("method name:%s ,type:%s\n", method.Name, method.Type) } //method name:GetName ,type:func(main.Person) //指针 //指针或值的方法都包含在内,也就是说值实现的方法指针也实现了对应方法 person1 := reflect.TypeOf(&Person{}) methodNum1 := person1.NumMethod() for i:=0;i<methodNum1;i++{ method1 := person1.Method(i) fmt.Printf("method name:%s ,type:%s\n", method1.Name, method1.Type) } //method name:GetAge ,type:func(*main.Person) //method name:GetName ,type:func(*main.Person) //method name:GetSex ,type:func(*main.Person) ``` #### 函数信息 ``` func calc(a,b int) int{ return a + b } tFunc := reflect.TypeOf(calc) fmt.Println(tFunc)//func(int, int) int //获取入参数量 inNum := tFunc.NumIn() fmt.Println(inNum)//2 for i := 0; i < inNum; i++ { argIn := tFunc.In(i) fmt.Printf("第%d个输入参数的类型%s\n", i, argIn) //第0个输入参数的类型int } //获取出参数量 outNum := tFunc.NumOut() fmt.Println(outNum )//1 for i := 0; i < outNum; i++ { argOut := tFunc.In(i) fmt.Printf("第%d个输出参数的类型%s\n", i, argOut) //第0个输出参数的类型int } ``` #### 是否实现了某个接口 ``` //通过reflect.TypeOf((*<interface>)(nil)).Elem()获得接口类型。 //因为People是个接口不能创建实例,所以把nil强制转为*Users类型 typeOnUsers := reflect.TypeOf((*Users)(nil)).Elem() fmt.Printf("typeOnUsers kind is interface %t\n", typeOnUsers.Kind() == reflect.Interface) //typeOnUsers kind is interface true //如果值类型实现了接口,则指针类型也实现了接口;反之不成立 u1 := reflect.TypeOf(Person{}) u2 := reflect.TypeOf(&Person{}) fmt.Printf("u1 implements Users interface %t\n", u1.Implements(typeOnUsers)) //u1 implements Users interface true fmt.Printf("u2 implements Users interface %t\n", u2.Implements(typeOnUsers)) //u2 implements Users interface true typeOnUsersPtr := reflect.TypeOf((*UsersPtr)(nil)).Elem() fmt.Printf("u1 implements Users interface %t\n", u1.Implements(typeOnUsersPtr)) //u1 implements Users interface false fmt.Printf("u2 implements Users interface %t\n", u2.Implements(typeOnUsersPtr)) //u2 implements Users interface true ``` ### reflect.Value 用户获取任何表达式的反射值 ``` //返回Value类型变量 func ValueOf(i interface{}) Value //Value类型的结构体 type Value struct { // 表示的值的类型 typ *rtype // 指向原始数据的指针 ptr unsafe.Pointer //标志位保存有关该值的元数据 flag } ``` | 方法名 | 说  明 | | --- | --- | | Interface() interface {} | 将值以 interface{} 类型返回,可以通过类型断言转换为指定类型 | | Int() int64 | 将值以 int 类型返回,所有有符号整型均可以此方式返回 | | Uint() uint64 | 将值以 uint 类型返回,所有无符号整型均可以此方式返回 | | Float() float64 | 将值以双精度(float64)类型返回,所有浮点数(float32、float64)均可以此方式返回 | | Bool() bool | 将值以 bool 类型返回 | | Bytes() \[\]bytes | 将值以字节数组 \[\]bytes 类型返回 | | String() string | 将值以字符串类型返回 | ``` // 返回value是否可以被寻址 func (v Value) CanAddr() bool // 类似& value寻址返回包装value func (v Value) Addr() Value // 返回value是否可以被修改 需要CanAddr func (v Value) CanSet() bool // 类似* value解引用后返回包装value // 需要prt interface func (v Value) Elem() Value // 方法调用 func (v Value) Call(in []Value) []Value // 方法调用 可变参数使用数组传入 func (v Value) CallSlice(in []Value) []Value func (v Value) TryRecv() (x Value, ok bool) func (v Value) Recv() (x Value, ok bool) func (v Value) TrySend(x Value) bool func (v Value) Send(x Value) func (v Value) Close() func (v Value) Field(i int) Value func (v Value) FieldByIndex(index []int) Value func (v Value) FieldByName(name string) Value func (v Value) FieldByNameFunc(match func(string) bool) Value func (v Value) Method(i int) Value func (v Value) NumMethod() int func (v Value) NumField() int func (v Value) MethodByName(name string) Value func (v Value) Index(i int) Value func (v Value) Type() Type func (v Value) Kind() Kind func (v Value) Convert(t Type) Value func (v Value) UnsafeAddr() uintptr // 返回子节数组 func (v Value) Bytes() []byte func (v Value) SetBytes(x []byte) // 返回string类型 func (v Value) String() string func (v Value) SetString(x string) // 返回interface类型 func (v Value) CanInterface() bool func (v Value) Interface() (i interface{}) func (v Value) InterfaceData() [2]uintptr func (v Value) Set(x Value) // 返回float64 func (v Value) Float() float64 func (v Value) SetFloat(x float64) func (v Value) OverflowFloat(x float64) bool // 返回int64 func (v Value) Int() int64 func (v Value) SetInt(x int64) func (v Value) OverflowInt(x int64) bool // 返回uint64 func (v Value) Uint() uint64 func (v Value) SetUint(x uint64) func (v Value) OverflowUint(x uint64) bool // 返回bool func (v Value) Bool() bool func (v Value) SetBool(x bool) // 返回complex128 func (v Value) Complex() complex128 func (v Value) SetComplex(x complex128) func (v Value) OverflowComplex(x complex128) bool // map操作 func (v Value) SetMapIndex(key, elem Value) func (v Value) MapIndex(key Value) Value func (v Value) MapKeys() []Value func (v Value) MapRange() *MapIter // chan func interface map ptr slice 返回值是否位nil func (v Value) IsNil() bool // 返回value本身是否有效 func (v Value) IsValid() bool // 返回value是否位该对应类型的零值 func (v Value) IsZero() bool ``` #### 获取Value类型 ``` x := 188 tInt := reflect.ValueOf(x) fmt.Println(tInt,tInt.Type()) // 188 fmt.Println(tInt.Type()) // int value类型转type name := "叫我小叮当啊" tSring := reflect.ValueOf(name) fmt.Println(tSring,tSring.Type()) // 叫我小叮当啊 fmt.Println(tSring.Type()) //string value类型转type personPtrValue := reflect.ValueOf(&Person{ Name: "叫我小叮当啊", age: 18, gender: 1, }) fmt.Println(personPtrValue) //&{叫我小叮当啊 18 1} fmt.Println(personPtrValue.Type()) //Person value类型转type ``` #### 指针Value和非指针Value互相转换 ``` personValue := personPtrValue.Elem() //Elem() 指针Value转为非指针Value fmt.Println(personValue .Kind(), personPtrValue.Kind()) //struct ptr personPtrValueNew := personValue .Addr() //Addr() 非指针Value转为指针Value fmt.Println(personValue.Kind(), personPtrValueNew .Kind()) //struct ptr ``` #### Value 转换到 原始类型 ``` //通过interface()方法把value类型转到interface{}类型,再类型断言转换,强制转换 //或者直接value类型直接Int()或者其他方法直接转换 x := 188 tInt := reflect.ValueOf(x) fmt.Printf("%d %d", tInt.Interface().(int), tInt.Int())//188 188 name := "叫我小叮当啊" tSring := reflect.ValueOf(name) fmt.Printf("%s %s", tSring .Interface().(string), tSring .String()) personPtrValue := reflect.ValueOf(&Person{ Name: "叫我小叮当啊", age: 18, gender: 1, }) p := personPtrValue.Interface().(*Person)//这块用*主要是上面是指针 fmt.Println(p.Name,p.age,p.gender)//叫我小叮当啊 18 1 ``` #### 空value判断 ``` var x interface{} = nil xp := reflect.ValueOf(x) if xp.IsValid() { fmt.Println("xp is valid") }else{ fmt.Println("xp not valid") //进入到这里 } `x`的值设为nil,所以没有具体的类型,因此`xp.IsValid()`函数返回的值是false,表示这个变量是无效的。 var x interface{} = 10 xps := reflect.ValueOf(x) if xps.IsValid() { fmt.Println("xps is valid") //进入到这里 fmt.Printf("xps 的值是0值吗 %t\n", xps.IsZero())//xps 的值是0值吗 false }else{ fmt.Println("xps not valid") } `x`的值设为一个整数类型的值10.由于`x`是一个空接口类型,因此在将它传递给`reflect.ValueOf()`函数之后,变量`xps`的具体类型会被自动地识别为整数类型`int` var person *Person = nil p := reflect.ValueOf(person) if p.IsValid() { fmt.Println("person is valid") //进入到这里 fmt.Printf("p 的值是nil %t\n", p.IsNil())//p 的值是nil true fmt.Printf("xps 的值是0值吗 %t\n", p.IsZero())//xps 的值是0值吗 true }else{ fmt.Println("person not valid") } ``` **谨记在调用类似IsZero(),IsNil()之前一定用IsValid()确认是否有效,否则会panic** #### Value修改值 **要想修改原始数据的值,给ValueOf传的必须是指针,而指针Value不能调用Set和FieldByName方法,所以得先通过Elem()转为非指针Value。未导出成员的值不能通过反射进行修改。** ##### 修改原始值 ``` var i int = 10 iInt := reflect.ValueOf(&i) iInt.Elem().SetInt(8) fmt.Println(i)// 8 var s string = "叫我小叮当啊" iString := reflect.ValueOf(&s) iString.Elem().SetString("叫我老叮当啊") fmt.Println(s)// 叫我老叮当啊 ``` **为了提升代码的健壮性,在调用Setxx()时,提前用CanSet判断,以免发生panic** ``` person := reflect.ValueOf(&Person{ Name: "叫我小叮当啊", age: 18, gender: 1, }) //不可导出字段不能设置 age := person.Elem().FieldByName("age") if age.CanSet(){ fmt.Println("can set") }else{ fmt.Println("not can set") //进入这里 } //可设置字段 name := person.Elem().FieldByName("Name") if name.CanSet(){ name.SetString("啊哈哈") fmt.Println(name) //啊哈哈 }else{ fmt.Println("not can set") } ``` ##### 修改slice ``` persons := make([]*Person,2,5) persons[0] = &Person{ Name: "叫我小叮当啊", age: 18, gender: 1, } persons[1] = &Person{ Name: "大雄", age: 28, gender: 2, } p := reflect.ValueOf(&persons) if p.Elem().Len() > 0 { p.Elem().Index(0).Elem().FieldByName("Name").SetString("hahah") fmt.Println(persons[0].Name)//hahah } //修改cap 初始是2 //设置的cap大小必须原始的len到cap之间,即只能把cap改小 p.Elem().SetCap(3) fmt.Println(cap(persons))// 3 //修改len,设置时注意cap的大小 p.Elem().SetLen(3) p.Elem().Index(2).Set(reflect.ValueOf(&Person{ Name: "静香", age: 28, gender: 2, })) fmt.Println(persons[2].Name) //静香 ``` ##### 修改map ``` persons := make(map[int]*Person,5) persons[0] = &Person{ Name: "叫我小叮当啊", age: 18, gender: 1, } p1 := &Person{ Name: "大雄", age: 28, gender: 2, } pV := reflect.ValueOf(&persons) pV.Elem().SetMapIndex(reflect.ValueOf(1),reflect.ValueOf(p1)) fmt.Println(persons[1])//&{大雄 28 2} //修改值 pV.Elem().MapIndex(reflect.ValueOf(1)).Elem().FieldByName("Name").SetString("胖虎") fmt.Println(persons[1])//&{胖虎 28 2} ``` #### 创建对象 ##### 创建slice ``` var users []Person usersType := reflect.TypeOf(users) usersValue := reflect.MakeSlice(usersType, 1,2) p1 := Person{ Name: "大雄", age: 28, gender: 2, } usersValue.Index(0).Set(reflect.ValueOf(p1)) user := usersValue.Interface().([]Person) fmt.Println(user)//[{大雄 28 2}] ``` ##### 创建map ``` var users map[int]*Person usersType := reflect.TypeOf(users) //usersValue := reflect.MakeMap(usersType)//这个可以创建 usersValue := reflect.MakeMapWithSize(usersType,3)//这个也可以 user := &Person{ Name: "大雄", age: 28, gender: 2, } usersValue.SetMapIndex(reflect.ValueOf(1),reflect.ValueOf(user)) usersValue.MapIndex(reflect.ValueOf(1)).Elem().FieldByName("Name").SetString("小叮当") values := usersValue.Interface().(map[int]*Person) fmt.Println(values[1])//&{小叮当 28 2} ``` ##### 创建struct ``` tmp := reflect.TypeOf(Person{}) value := reflect.New(tmp)//new 转化到指针 value value.Elem().FieldByName("Name").SetString("小夫") fmt.Println(value)//&{小夫 0 0} ```