B5net

人生是场无尽旅途,欢声笑语,踟蹰彷徨,走过的是岁月,路过的是迷茫。向前,是希望极光;回首,是悠长深巷。

go中reflect反射的使用笔记

Published on:2022-11-02
一、介绍

reflect包实现了运行时反射,允许程序操作任意类型的对象。
典型用法是用静态类型interface{}保存一个值,
通过调用TypeOf获取其动态类型信息,该函数返回一个Type类型值。
调用ValueOf函数返回一个Value类型值,该值代表运行时的数据。
Zero接受一个Type类型参数并返回一个代表该类型零值的Value类型值。

二、理解


TypeOf 获取参数的类型相关信息,若是结构体,也可以获取结构体成员相关信息。
ValueOf 获取参数的值的相关信息,可以通过调用Type() 获取TypeOf的类型信息。
如果只是获取类型相关信息信息可以使用TypeOf
若需要操作值或值和类型 可以只是用ValueOf
如果参数是一个指针引用类型 Ptr 所有得操作需要加上 Elem()

三、TypeOf常用总结


Kind() Kind  返回参数类型 reflect包下的常量  Array Chan  Func Interface Map  Ptr Slice String  Struct 等
Name() string 返回自定义类型的名称。例如自己定义的 type TestInfo struct 类型 会返回TestInfo, 否则返回""

Len() int  返回map、array、slice、chan类型的长度

结构体相关的操作
NumField() int                    返回结构体struct类型的成员的数量
Field(i int) StructField         返回struct类型的第i个字段的类型
FieldByIndex(index []int) StructField  参数为StructField中的Index
FieldByName(name string) (StructField, bool)   通过名称获取某个成员

type StructField struct {
    Name    string  // 字段的名字
    Type      Type      // 字段的类型
    Tag       StructTag // 字段的标签 可以通过改成员获取标签信息
    Index     []int     // 用于Type.FieldByIndex时的索引切片
    PkgPath string
    Offset    uintptr 
    Anonymous bool      // 是否匿名字段
}

四、ValueOf常用总结


Kind() Kind
Len() int 返回map、array、slice、chan类型的长度

IsValid() bool 返回是否持有一个值。如果v是Value零值会返回假

Interface() (i interface{}) 当前持有的值。注意返回的值,虽然是本身的类型,但在代码上下文中是不知道具体的类型,要使用需要进行类型转换
还有一些直接获取特定类型  Int() int64 , Float() float64 , Bool() bool , Bytes() []byte , String() string


Index(i int) Value 返回Array、Chan、Slice、String类型的第i个元素

Map集合相关操作
MapKeys() []Value  所有集合map的所有键的Value的切片
MapIndex(key Value) Value  返回key持有值为键对应的值的Value

结构体相关操作
NumField() int  返回结构体struct类型的成员的数量与TypeOf的方法一致
Field(i int) Value  返回结构体的第i个字段的值得Value
FieldByIndex(index []int) Value  返回索引序列指定的段的Value,参数为类型中的StructField.Index
FieldByName(name string) Value 返回类型名为name的字段的Value封装(会查找匿名字段及其子字段),如果未找到会返回Value零值。使用IsValid()进行判断是否找到

五、代码示例


将any(interface{})转为切片
func AnyToSlice(arr any) []any {
v := reflect.ValueOf(arr)
ptr := false
l := 0
if v.Kind() == reflect.Ptr {
if v.Elem().Kind() != reflect.Slice {
return nil
}
ptr = true
l = v.Elem().Len()
} else {
if v.Kind() != reflect.Slice {
return nil
}
l = v.Len()
}
ret := make([]interface{}, l)
for i := 0; i < l; i++ {
if ptr {
ret[i] = v.Elem().Index(i).Interface()
} else {
ret[i] = v.Index(i).Interface()
}
}
return ret
}

将struct转为map[string]any
func StructToMap(dest any, isJson bool) map[string]any {
t := reflect.TypeOf(dest)
if t.Kind() != reflect.Struct {
return nil
}
l := t.NumField()

var data = make(map[string]any)
v := reflect.ValueOf(dest)
for i := 0; i < l; i++ {
key := t.Field(i).Name
if isJson {
jsonKey := t.Field(i).Tag.Get("json")
if jsonKey != "" {
key = jsonKey
}
}
data[key] = v.Field(i).Interface()
}
return data
}


官方文档
type Type interface {
    // Kind返回该接口的具体分类
    Kind() Kind
    // Name返回该类型在自身包内的类型名,如果是未命名类型会返回""
    Name() string
    // PkgPath返回类型的包路径,即明确指定包的import路径,如"encoding/base64"
    // 如果类型为内建类型(string, error)或未命名类型(*T, struct{}, []int),会返回""
    PkgPath() string
    // 返回类型的字符串表示。该字符串可能会使用短包名(如用base64代替"encoding/base64")
    // 也不保证每个类型的字符串表示不同。如果要比较两个类型是否相等,请直接用Type类型比较。
    String() string
    // 返回要保存一个该类型的值需要多少字节;类似unsafe.Sizeof
    Size() uintptr
    // 返回当从内存中申请一个该类型值时,会对齐的字节数
    Align() int
    // 返回当该类型作为结构体的字段时,会对齐的字节数
    FieldAlign() int
    // 如果该类型实现了u代表的接口,会返回真
    Implements(u Type) bool
    // 如果该类型的值可以直接赋值给u代表的类型,返回真
    AssignableTo(u Type) bool
    // 如该类型的值可以转换为u代表的类型,返回真
    ConvertibleTo(u Type) bool
    // 返回该类型的字位数。如果该类型的Kind不是Int、Uint、Float或Complex,会panic
    Bits() int
    // 返回array类型的长度,如非数组类型将panic
    Len() int
    // 返回该类型的元素类型,如果该类型的Kind不是Array、Chan、Map、Ptr或Slice,会panic
    Elem() Type
    // 返回map类型的键的类型。如非映射类型将panic
    Key() Type
    // 返回一个channel类型的方向,如非通道类型将会panic
    ChanDir() ChanDir
    // 返回struct类型的字段数(匿名字段算作一个字段),如非结构体类型将panic
    NumField() int
    // 返回struct类型的第i个字段的类型,如非结构体或者i不在[0, NumField())内将会panic
    Field(i int) StructField
    // 返回索引序列指定的嵌套字段的类型,
    // 等价于用索引中每个值链式调用本方法,如非结构体将会panic
    FieldByIndex(index []int) StructField
    // 返回该类型名为name的字段(会查找匿名字段及其子字段),
    // 布尔值说明是否找到,如非结构体将panic
    FieldByName(name string) (StructField, bool)
    // 返回该类型第一个字段名满足函数match的字段,布尔值说明是否找到,如非结构体将会panic
    FieldByNameFunc(match func(string) bool) (StructField, bool)
    // 如果函数类型的最后一个输入参数是"..."形式的参数,IsVariadic返回真
    // 如果这样,t.In(t.NumIn() - 1)返回参数的隐式的实际类型(声明类型的切片)
    // 如非函数类型将panic
    IsVariadic() bool
    // 返回func类型的参数个数,如果不是函数,将会panic
    NumIn() int
    // 返回func类型的第i个参数的类型,如非函数或者i不在[0, NumIn())内将会panic
    In(i int) Type
    // 返回func类型的返回值个数,如果不是函数,将会panic
    NumOut() int
    // 返回func类型的第i个返回值的类型,如非函数或者i不在[0, NumOut())内将会panic
    Out(i int) Type
    // 返回该类型的方法集中方法的数目
    // 匿名字段的方法会被计算;主体类型的方法会屏蔽匿名字段的同名方法;
    // 匿名字段导致的歧义方法会滤除
    NumMethod() int
    // 返回该类型方法集中的第i个方法,i不在[0, NumMethod())范围内时,将导致panic
    // 对非接口类型T或*T,返回值的Type字段和Func字段描述方法的未绑定函数状态
    // 对接口类型,返回值的Type字段描述方法的签名,Func字段为nil
    Method(int) Method
    // 根据方法名返回该类型方法集中的方法,使用一个布尔值说明是否发现该方法
    // 对非接口类型T或*T,返回值的Type字段和Func字段描述方法的未绑定函数状态
    // 对接口类型,返回值的Type字段描述方法的签名,Func字段为nil
    MethodByName(string) (Method, bool)
    // 内含隐藏或非导出方法
}

type Value
func ValueOf(i interface{}) Value
func Zero(typ Type) Value
func New(typ Type) Value
func NewAt(typ Type, p unsafe.Pointer) Value
func Indirect(v Value) Value
func MakeSlice(typ Type, len, cap int) Value
func MakeMap(typ Type) Value
func MakeChan(typ Type, buffer int) Value
func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value
func Append(s Value, x ...Value) Value
func AppendSlice(s, t Value) Value
func (v Value) IsValid() bool
func (v Value) IsNil() bool
func (v Value) Kind() Kind
func (v Value) Type() Type
func (v Value) Convert(t Type) Value
func (v Value) Elem() Value
func (v Value) Bool() bool
func (v Value) Int() int64
func (v Value) OverflowInt(x int64) bool
func (v Value) Uint() uint64
func (v Value) OverflowUint(x uint64) bool
func (v Value) Float() float64
func (v Value) OverflowFloat(x float64) bool
func (v Value) Complex() complex128
func (v Value) OverflowComplex(x complex128) bool
func (v Value) Bytes() []byte
func (v Value) String() string
func (v Value) Pointer() uintptr
func (v Value) InterfaceData() [2]uintptr
func (v Value) Slice(i, j int) Value
func (v Value) Slice3(i, j, k int) Value
func (v Value) Cap() int
func (v Value) Len() int
func (v Value) Index(i int) Value
func (v Value) MapIndex(key Value) Value
func (v Value) MapKeys() []Value
func (v Value) NumField() int
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) Recv() (x Value, ok bool)
func (v Value) TryRecv() (x Value, ok bool)
func (v Value) Send(x Value)
func (v Value) TrySend(x Value) bool
func (v Value) Close()
func (v Value) Call(in []Value) []Value
func (v Value) CallSlice(in []Value) []Value
func (v Value) NumMethod() int
func (v Value) Method(i int) Value
func (v Value) MethodByName(name string) Value
func (v Value) CanAddr() bool
func (v Value) Addr() Value
func (v Value) UnsafeAddr() uintptr
func (v Value) CanInterface() bool
func (v Value) Interface() (i interface{})
func (v Value) CanSet() bool
func (v Value) SetBool(x bool)
func (v Value) SetInt(x int64)
func (v Value) SetUint(x uint64)
func (v Value) SetFloat(x float64)
func (v Value) SetComplex(x complex128)
func (v Value) SetBytes(x []byte)
func (v Value) SetString(x string)
func (v Value) SetPointer(x unsafe.Pointer)
func (v Value) SetCap(n int)
func (v Value) SetLen(n int)
func (v Value) SetMapIndex(key, val Value)
func (v Value) Set(x Value)
func Copy(dst, src Value) int
func DeepEqual(a1, a2 interface{}) bool

留言列表(0)

    留言

    B5net

    人生是场无尽旅途,欢声笑语,踟蹰彷徨,走过的是岁月,路过的是迷茫。向前,是希望极光;回首,是悠长深巷。

    开源项目
    最新评论
    小白 :大佬您好 请问一下 http://b5laravelcmf.b5net.com/admin这个演示网址的全部代码有吗,gitee上不全呢,还能提供一下吗,感激不尽阿
    tz :大佬 B5YiiCMF 还开放吗
    weifox on GoLang常用的三方库 :还有 https://github.com/golang-module/carbon
    php :关于导出功能:1、B5thinkCMF部署后 参数的导出功能点击后就白屏了,不知道是哪里有问题?2、人员部门的导出功能没看懂怎么配置的? 只是启用exportshow=true吗 方便的话请答复下,谢谢!
    初学者 :您好! 部署了您的B5ThinkCMF,请教下 使用新增功能如何实现二级联动呢 ?谢谢
    11 :22
    pcy :前排围观
    Louis :冰舞的博客使用yii框架做的吧,B5ThinkCMF在本地部署后,登录系统的响应时间要比B5YiiCMF的登录时间长,还有一些Bug待修复
    34 :感谢你的开源项目
    文章分类