[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}
```
- Go准备工作
- 依赖管理
- Go基础
- 1、变量和常量
- 2、基本数据类型
- 3、运算符
- 4、流程控制
- 5、数组
- 数组声明和初始化
- 遍历
- 数组是值类型
- 6、切片
- 定义
- slice其他内容
- 7、map
- 8、函数
- 函数基础
- 函数进阶
- 9、指针
- 10、结构体
- 类型别名和自定义类型
- 结构体
- 11、接口
- 12、反射
- 13、并发
- 14、网络编程
- 15、单元测试
- Go常用库/包
- Context
- time
- strings/strconv
- file
- http
- Go常用第三方包
- Go优化
- Go问题排查
- Go框架
- 基础知识点的思考
- 面试题
- 八股文
- 操作系统
- 整理一份资料
- interface
- array
- slice
- map
- MUTEX
- RWMUTEX
- Channel
- waitGroup
- context
- reflect
- gc
- GMP和CSP
- Select
- Docker
- 基本命令
- dockerfile
- docker-compose
- rpc和grpc
- consul和etcd
- ETCD
- consul
- gin
- 一些小点
- 树
- K8s
- ES
- pprof
- mycat
- nginx
- 整理后的面试题
- 基础
- Map
- Chan
- GC
- GMP
- 并发
- 内存
- 算法
- docker