本教材由知了传课辛苦制作而成,仅供学习使用,请勿用于商业用途!如进行转载请务必注明出处!谢谢!

反射

一、什么是反射?

Go 语言提供了一种机制在运行时更新变量和检查它们的值、调用它们的方法,但是在编译时并不知道这些变量的具体类型,这称为反射机制

反射就是动态的获取变量类型信息值信息的机制

反射能够在运行时检查类型

reflect.TypeOf – 获取类型信息,使用%T就是这个类型

reflect.ValueOf – 获取值信息

二、使用场景

1.做对象的序列化,构建适用于不同类型的工具

2.序列化和反序列化,比如json, protobuf等各种数据协议

3.各种数据库的ORM,比如gorm,sqlx等数据库中间件

4.配置文件解析相关的库,比如yaml、ini等

5.编写一个函数,但是并不知道传给你的参数类型是什么

6.需要根据某些条件决定调用哪个函数,调用的函数是字符串参数

三、go语言中的反射使用

1.TypeOf查看类型信息

func TypeOf(age interface{}) { fmt.Println(reflect.TypeOf(age)) type_age := reflect.TypeOf(age) switch type_age.Kind() { case reflect.Int64: fmt.Println("age的类型是int64") case reflect.Int: fmt.Println("age的类型是int") } } func main() { var age int = 3 TypeOf(age) }

2.Type接口方法

  • Align() int:在内存中的对齐方式
  • FieldAlign() int:字段在内存中的对齐方式
  • Method(int) Method:根据索引获取 类型的方法
  • MethodByName(string) (Method, bool):根据方法名称获取类型的方法
  • NumMethod() int:方法数量
  • Name() string:在包中定义的名称
  • PkgPath() string:包的名称
  • Size() uintptr:类型的值在分配内存时的大小,功能和 unsafe.SizeOf 一样
  • Golang中的sring内部实现由两部分组成,一部分是指向字符串起始地址的指针,
    另一部分是字符串的长度,两部分各是8字节,所以一共16字节
  • String() string:类型的字符串描述,不要通过 String 来判断两种类型是否一致
  • Kind() Kind:类别
  • Implements(u Type) bool:类型是否实现了u接口
  • AssignableTo(u Type) bool:类型的值可否赋值给 u 类型
  • ConvertibleTo(u Type) bool:类型的值可否转换为 u 类型
  • Comparable() bool:类型的值可否进行比较操作
  • Bits() int:获取数值类型的位宽,t 必须是整型、浮点型、复数型
  • ChanDir() ChanDir:获取通道的方向
  • IsVariadic() bool:判断函数是否具有可变参数。
  • Elem() Type: 获取元素类型、获取指针所指对象类型,获取接口的动态类型
  • Field(i int) StructField:根据索引获取字段
  • FieldByIndex(index []int) StructField:根据索引链获取嵌套字段
  • FieldByName(name string) (StructField, bool):根据名称获取字段
  • FieldByNameFunc(match func(string) bool) (StructField, bool):根据指定的匹配函数获取字段
  • In(i int) Type:根据索引获取函数的参数信息
  • Key() Type:获取映射的键类型
  • Len() int:获取数组的元素个数
  • NumField() int:获取字段数量
  • NumIn() int:获取函数的参数数量
  • NumOut() int: 获取函数的返回值数量
  • Out(i int) Type:根据索引获取函数的返回值信息

3.ValueOf查看值信息

func ValueOf(age interface{}) { fmt.Println(reflect.ValueOf(age)) value_age := reflect.ValueOf(age) fmt.Println(value_age.Type()) fmt.Println(value_age.String()) switch value_age.Kind() { case reflect.Int64: fmt.Println("age的类型是int64") case reflect.Int: fmt.Println("age的类型是int") } } func main() { var age int = 3 ValueOf(age) }

特点:值是动态的,可以获取类型(value_age.Type),获取值(value_age.Int()),也可以设置值

4.Value下的方法

  • func (v Value) Addr() Value: 获取 v 值的地址,相当于 & 取地址操作
  • func (v Value) Bool() bool:获取 v 值的内容,如果 v 值不是布尔型,则 panic
  • func (v Value) Bytes() []byte:获取 v 值的内容,如果 v 值不是字节切片,则 panic
  • func (v Value) CanAddr() bool:判断 v 值是否可寻址
  • func (v Value) CanSet() bool: 判断 v 值是否可以被修改。只有可寻址的 v 值可被修改
  • func (v Value) Call(in []Value) []Value:通过参数列表 in 调用 v 值所代表的函数,定参和变参都可以
  • func (v Value) CallSlice(in []Value) []Value:CallSlice 只能调用变参函数
  • func (v Value) Cap() int:获取 v 值的容量,必须是Array, Chan, or Slice
  • func (v Value) Close() :关闭通道,v 值必须是通道
  • func (v Value) Complex() complex128:获取 v 值的内容,如果 v 值不是复数型,则 panic
  • func (v Value) Elem() Value:获取 指针所指的对象 或 接口所包含的对象
  • func (v Value) Field(i int) Value:根据索引获取 v 值的字段,v 值必须是结构体
  • func (v Value) FieldByIndex(index []int) Value:根据索引链获取 v 值的嵌套字段,v 值必须是结构体
  • func (v Value) FieldByName(name string) Value: 根据名称获取 v 值的字段,v 值必须是结构体
  • func (v Value) FieldByNameFunc(match func(string) bool) Value:根据匹配函数获取 v 值的字段,v 值必须是结构体
  • func (v Value) Float() float64:获取 v 值的内容,如果 v 值不是浮点型,则 panic
  • func (v Value) Index(i int) Value:获取 v 值的第 i 个元素,v 值必须是Array, Slice, or String,i 不能超出范围
  • func (v Value) Int() int64:获取 v 值的内容,如果 v 值不是有符号整型,则 panic
  • func (v Value) CanInterface() bool:判断 v 值是否可以转换为接口类型
  • func (v Value) Interface() (i interface{}):将 v 值转换为空接口类型。v 值必须可转换为接口类型
  • func (v Value) InterfaceData() [2]uintptr:使用一对 uintptr 返回接口的数据
  • func (v Value) IsNil() bool: 判断 v 值是否为 nil,v 值必须是chan, func, interface, map, pointer, or slice
  • func (v Value) IsValid() bool:判断 v 本身(不是 v 值)是否为零值。
  • func (v Value) IsZero() bool:是否是其自身类型的零值
  • func (v Value) Kind() Kind: 返回 v 值的类别
  • func (v Value) Len() int:获取 v 值的长度,v 值必须是Array, Chan, Map, Slice, or String
  • func (v Value) MapIndex(key Value) Value:根据 key 键获取 v 值的内容,v 值必须是映射
  • func (v Value) MapKeys() []Value: 获取 v 值的所有键的无序列表,v 值必须是映射
  • func (v Value) MapRange() *MapIter:返回可循环的迭代器
iter := reflect.ValueOf(m).MapRange()
for iter.Next() {
k := iter.Key()
v := iter.Value()
...
}
  • func (v Value) Method(i int) Value:根据索引获取 v 值的方法,方法必须存在,否则 panic
  • func (v Value) NumMethod() int:获取 v 的方法数量
  • func (v Value) MethodByName(name string) Value:根据名称获取 v 值的方法
  • func (v Value) NumField() int:获取 v 值的字段数量,v 值必须是结构体
  • func (v Value) OverflowComplex(x complex128) bool: 判断 x 是否超出 v 值的取值范围,v 值必须是复数型
  • func (v Value) OverflowFloat(x float64) bool: 判断 x 是否超出 v 值的取值范围,v 值必须是浮点型
  • func (v Value) OverflowInt(x int64) bool:判断 x 是否超出 v 值的取值范围,v 值必须是有符号整型(int和uint的区别,int可以有负数,uint不能有负数)
  • func (v Value) OverflowUint(x uint64) bool:判断 x 是否超出 v 值的取值范围,v 值必须是无符号整型
  • func (v Value) Pointer() uintptr: v 值转换为 uintptr 类型,v 值必须是Chan, Func, Map, Ptr, Slice, or UnsafePointer
  • func (v Value) Recv() (x Value, ok bool):接收数据(会阻塞),v 值必须是可读通道
  • func (v Value) Send(x Value):发送数据(会阻塞),v 值必须是可写通道
  • func (v Value) Set(x Value) :设置 v 值的内容,v 值必须可修改,x 必须可以赋值给 v 值
  • func (v Value) SetBool(x bool):设置 v 值的内容,v 值必须是布尔型
  • func (v Value) SetBytes(x []byte):设置 v 值的内容,v 值必须是字节切片
  • func (v Value) SetComplex(x complex128):设置 v 值的内容,v 值必须是复数型。
  • func (v Value) SetFloat(x float64):设置 v 值的内容,v 值必须是浮点型
  • func (v Value) SetInt(x int64):设置 v 值的内容,v 值必须是有符号整型
  • func (v Value) SetLen(n int):设置 v 值的长度,v 值必须是切片,n 不能超出范围,不能为负数。
  • func (v Value) SetCap(n int):设置 v 值的内容,v 值必须是切片,n 不能超出范围,不能小于 Len。
  • func (v Value) SetMapIndex(key, elem Value) :设置 v 值的键和值,如果键存在,则修改其值,如果键不存在,则添加键和值
  • func (v Value) SetUint(x uint64):设置 v 值的内容,v 值必须是无符号整型
  • func (v Value) SetPointer(x unsafe.Pointer):将 UnsafePointer 类别的 v 值修改为 x,v 值必须是 UnsafePointer 类别,必须可修改
  • func (v Value) SetString(x string):设置 v 值的内容,v 值必须是字符串。
  • func (v Value) Slice(i, j int) Value :获取 v 值的切片,切片长度 = j - i,切片容量 = v.Cap() - i
  • func (v Value) Slice3(i, j, k int) Value:切片长度 = j - i,切片容量 = k - i
  • func (v Value) String() string:获取 v 值的字符串描述
  • func (v Value) TryRecv() (x Value, ok bool):尝试接收数据(不会阻塞),v 值必须是可读通道。
  • func (v Value) TrySend(x Value) bool:尝试发送数据(不会阻塞),v 值必须是可写通道
  • func (v Value) Type() Type:获取 v 值的类型
  • func (v Value) Uint() uint64:获取 v 值的内容,如果 v 值不是无符号整型(包括 uintptr),则 panic
  • func (v Value) UnsafeAddr() uintptr:获取 v 值的地址。v 值必须是可寻址类型(CanAddr)
  • func (v Value) Convert(t Type) Value: 将 v 值转换为 t 类型,v 值必须可转换为 t 类型,否则 panic

动态设置值的方式:需要注意,值类型不能改变原值,需要使用指针

func SetValue(age int) { value_age := reflect.ValueOf(&age) //这里必须使用指针的方式 fmt.Println(value_age.Type()) // *int的赋值:*age = 4 value_age.Elem().SetInt(4) // Elem returns a type's element type. fmt.Printf("After set x is %v\n",age) } func main() { var age int = 3 SetValue(age) }

TypeOf() 函数返回一个接口,这个接口定义了一系列方法,利用这些方法可以获取关于类型的所有信息;

ValueOf() 函数返回一个结构体变量,包含类型信息以及实际值。

1226人已阅读,今天你学习了吗?

添加新回复