首页 > 其他分享 >go反射使用及proto协议字段随机动态赋值

go反射使用及proto协议字段随机动态赋值

时间:2023-07-01 22:12:16浏览次数:61  
标签:case tmp proto value reflect field go Type 赋值

1. 基本概念

  • Go 语言的反射是一种在运行时动态访问程序元数据的能力。反射可以让我们在运行时检查类型和变量,例如它的大小、方法和动态的值等。这种机制让我们可以编写更加通用的函数和类型,而不需要关心具体的类型。
  • 在 Go 语言中,反射的实现主要依赖于两种类型:TypeValue。这两种类型都定义在 reflect 包中。  
    • Type:代表 Go 语言中的类型。通过 Type,我们可以获取类型的名称、种类、包路径、大小、是否为指针类型、是否为接口类型、是否可导出等信息。我们可以通过 reflect.TypeOf 函数获取一个值的 Type
    • Value:代表 Go 语言中的值。通过 Value,我们可以获取值的类型、种类、是否可导出、是否可寻址、是否可修改等信息。我们还可以通过 Value 修改值、调用方法等。我们可以通过 reflect.ValueOf 函数获取一个值的 Value
  • 在 Go 语言的反射机制中,还有一个重要的概念是种类(Kind)。每个 Type 都有一个对应的种类,例如 intfloat64structpointer 等。我们可以通过 Type.Kind 方法获取一个类型的种类。
  • Go 语言的反射机制虽然强大,但也有一些限制。例如,我们不能通过反射创建一个接口值的具体值,也不能获取一个非导出字段的 Value。此外,使用反射会有一定的性能开销,因此在编写性能敏感的代码时,应尽量避免使用反射。
  • 总的来说,Go 语言的反射是通过 TypeValue 这两种类型,以及种类(Kind)这个概念来实现的。通过反射,我们可以在运行时动态地访问和修改程序的元数据。

2. 接口

  a) reflect.TypeOf(xxx)

  b) reflect.ValueOf(xxx)

  c) reflect.New(xxx)

  返回的都是指针,如果需要获取对象需要通过 ret.Elem() 获取

3. 用例

//随机给proto协议对象赋值
func randMsg() (int32, proto.Message) {
    var msgId int32     if common.Random(0, 4) == 0 {         //25%的概率发送ack or ntf协议         var msgIds []int32         for id, name := range pb_server.MessageID_name {             if strings.Contains(name, "ACK") || strings.Contains(name, "NTF") {                 msgIds = append(msgIds, id)             }         }         msgId = msgIds[common.Random(0, len(msgIds))]     } else {         //75%的概率发送req协议         var msgIds []int32         for id, name := range pb_server.MessageID_name {             if strings.Contains(name, "REQ") {                 msgIds = append(msgIds, id)             }         }         msgId = msgIds[common.Random(0, len(msgIds))]     }

    //msgId = 1064 //slice test
    //msgId = 1111 //map test

    proname := "server." + common.ProtoMsgTrans(pb_server.MessageID_name[msgId])
    obj, err := protoregistry.GlobalTypes.FindMessageByName(protoreflect.FullName(proname))
    if err != nil {
        l4g.Debug("RandMsgEvent name:%s err:%v", proname, err)
        return 0, nil
    }

    msg := proto.MessageV1(obj.New()) 
    l4g.Debug("RandMsgEvent name:%s", proname)
    // 获取 Message 的反射类型和值
    msgType := reflect.TypeOf(msg).Elem()
    msgValue := reflect.ValueOf(msg).Elem()
    foreachField(msgType, &msgValue)
    return msgId, msg
}
func foreachField(tp reflect.Type, value *reflect.Value) {
    for i := 0; i < tp.NumField(); i++ {
        field := tp.Field(i)
        if strings.HasPrefix(field.Name, "XXX_") {
            continue
        }
        //l4g.Debug("forechField i:%d name:%s type:%v", i, field.Name, field.Type.Kind().String())

        fieldValue := value.Field(i)
        setValue(&field, &fieldValue)
    }
}
 
func setValue(field *reflect.StructField, value *reflect.Value) {
    switch field.Type.Kind() {
    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
        {
            var tmp int64
            switch field.Type.Kind() {
            case reflect.Int:
                tmp = int64(math.MaxInt)
            case reflect.Int8:
                tmp = int64(math.MaxInt8)
            case reflect.Int16:
                tmp = int64(math.MaxInt16)
            case reflect.Int32:
                tmp = int64(math.MaxInt32)
            case reflect.Int64:
                tmp = int64(math.MaxInt64)
            }
            rand := common.Random(0, 3)
            if rand == 0 {
                value.SetInt(int64(0))
            } else if rand == 1 {
                value.SetInt(int64(common.Random(0, int(tmp))))
            } else {
                value.SetInt(tmp)
            }
        }
    case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
        {
            var tmp uint64
            switch field.Type.Kind() {
            case reflect.Uint:
                tmp = uint64(math.MaxUint)
            case reflect.Uint8:
                tmp = uint64(math.MaxUint8)
            case reflect.Uint16:
                tmp = uint64(math.MaxUint16)
            case reflect.Uint32:
                tmp = uint64(math.MaxUint32)
            case reflect.Uint64:
                tmp = uint64(math.MaxUint64)
            }
            rand := common.Random(0, 3)
            if rand == 0 {
                value.SetUint(uint64(0))
            } else if rand == 1 {
                value.SetUint(uint64(common.Random(0, int(tmp)))) //tmp越界忽略
            } else {
                value.SetUint(tmp)
            }
        }
    case reflect.String:
        {
            value.SetString("hello world!!!")
        }
    case reflect.Float32, reflect.Float64:
        {
            value.SetFloat(float64(common.Random(0, 100)))
        }
    case reflect.Bool:
        {
            value.SetBool(common.Random(0, 2) == 0)
        }
    case reflect.Ptr:
        {
            newType := field.Type.Elem()
            newVal := reflect.New(newType).Elem()
            foreachField(newType, &newVal)
            value.Set(newVal.Addr())
        }
    case reflect.Struct:
        //proto生成的代码结构都是指针,无需实现
    case reflect.Slice:
        {
            sliceType := field.Type
            sliceLen := common.Random(1, 6) // 随机生成长度为 1 到 5 的切片
            newSlice := reflect.MakeSlice(sliceType, sliceLen, sliceLen)
            elemType := sliceType.Elem()
            for i := 0; i < sliceLen; i++ {
                elem := newSlice.Index(i)
                if elem.Type().Kind() == reflect.Ptr {
                    newElem := reflect.New(elem.Type().Elem()).Elem()
                    foreachField(elemType.Elem(), &newElem)
                    elem.Set(newElem.Addr())
                } else {
                    elemField := &reflect.StructField{
                        Name:      field.Name,
                        PkgPath:   field.PkgPath,
                        Type:      elemType,
                        Tag:       field.Tag,
                        Offset:    field.Offset,
                        Index:     field.Index,
                        Anonymous: field.Anonymous,
                    }
                    setValue(elemField, &elem)
                }
                newSlice.Index(i).Set(elem)
            }
            value.Set(newSlice)
        }
    case reflect.Map:
        {
            mapType := field.Type
            mapLen := common.Random(1, 6) // 随机生成长度为 1 到 5 的映射
            newMap := reflect.MakeMapWithSize(mapType, mapLen)
            keyType := mapType.Key()
            elemType := mapType.Elem()
            fmt.Println("map type:", mapType.Kind(), "elemType:", elemType.Kind())
            for i := 0; i < mapLen; i++ {
                //key
                newKey := reflect.New(keyType).Elem()
                keyField := reflect.StructField{
                    Name:      field.Name + "_key",
                    PkgPath:   field.PkgPath,
                    Type:      keyType,
                    Tag:       field.Tag,
                    Offset:    field.Offset,
                    Index:     field.Index,
                    Anonymous: field.Anonymous,
                }
                setValue(&keyField, &newKey)
                //value
                newElem := reflect.New(elemType).Elem()
                //fmt.Println("newElem kind:", newElem.Kind(), "typename:", newElem.Type().Name())
                if elemType.Kind() == reflect.Ptr {
                    tmpElem := reflect.New(newElem.Type().Elem()).Elem()
                    foreachField(elemType.Elem(), &tmpElem)
                    newElem.Set(tmpElem.Addr())
                } else if elemType.Kind() == reflect.Struct {
                    foreachField(elemType, &newElem)
                } else {
                    elemField := reflect.StructField{
                        Name:      field.Name + "_value",
                        PkgPath:   field.PkgPath,
                        Type:      elemType,
                        Tag:       field.Tag,
                        Offset:    field.Offset,
                        Index:     field.Index,
                        Anonymous: field.Anonymous,
                    }
                    setValue(&elemField, &newElem)
                }
                newMap.SetMapIndex(newKey, newElem)
            }
            value.Set(newMap)
        }
    default:
        {
            l4g.Error("setFieldValue unkown kind:%v name:%s", field.Type.Kind(), field.Name)
        }
    }
}

4. 总结:

   指针与对象转换 Kind(),Elem(),Addr(),CanSet(),Name()接口,要求区分返回的到底是指针还是对象实例

标签:case,tmp,proto,value,reflect,field,go,Type,赋值
From: https://www.cnblogs.com/Lucky-qin2013/p/17513259.html

相关文章

  • Golang实现图片与视频的缩略图生成
    图片与视频的缩略图是一个十分常见的需求,比如即时消息。这里摘取了Golang项目中的相关代码,分享图片与视频相关处理的开发经验。图片缩略图缩略图的尺寸分为两种规则:1)边长模式,生成正方形缩略图;2)宽高模式,又分三种:指定宽高、指定宽(高等比缩放)、指定高(宽等比缩放)。如果原图为png或gif,缩......
  • django优缺点 # ninja的优点可替代DRF
    摘抄:https://www.cnblogs.com/fnng/p/16084825.htmldjango优点通过脚手架创建项目/应用:不用考虑项目架构怎么设计。自带Admin后台:在没有前端的情况下,可以比较方便通过Admin对数据进行操作。自带常用模块:一个命令就能生成group、user、session...表,一般个系统都需要user表吧......
  • 嵌入式linux开发 | u-boot启动logo修改
    原文:https://zhuanlan.zhihu.com/p/582316377一、导读使用嵌入式linux作为设备的操作系统,当在设备上电启动后,希望显示开机logo。一般会经历以下几个流程:(1)运行芯片内部引导程序(2)运行引导加载程序(u-boot较为常用)(3)运行linux内核(4)运行用户根文件系统,在这个阶段,就会根据项目......
  • goorm php环境安装go 1.20
    1、下载golang最新版本1.20.5,并安装到/usr/local/go目录wgethttps://golang.google.cn/dl/go1.20.5.linux-amd64.tar.gztarzxfgo1.20.5.linux-amd64.tar.gztar-C/usr/local/-xzvfgo1.20.5.linux-amd64.tar.gz 2、创建GOPATH目录mkdir~/.go 3、设置环境变量G......
  • Comparing with traditional convex optimization methodology, what are advantages
    与传统的凸优化方法相比,粒子群算法有哪些优点 与传统的凸优化方法相比,粒子群优化(PSO)算法具有以下优点:全局搜索能力:PSO算法具有较强的全局搜索能力,能够在多个解空间中寻找最优解。由于粒子群在搜索过程中可以通过信息共享和合作,有助于避免陷入局部最优解。适应性和......
  • 智能计算理论:Please write down the procedure of PSO algorithm.
    粒子群优化(ParticleSwarmOptimization,PSO)算法是一种基于种群的优化算法,灵感来源于鸟群或鱼群的社会行为。下面是PSO算法的一般过程:初始化粒子群:创建一个粒子群,其中每个粒子表示问题的一个潜在解。在搜索空间内随机初始化粒子的位置和速度。评估适应度:根据每个粒子的当前位......
  • Docker 安装MongoDB
    Docker安装Consul单机模式使用root用户操作1、拉取官方的最新版本的镜像dockerpullmongo:latest2、创建主机挂载配置目录data目录存放mongodb数据库文件,删除重启容器不会丢失mkdir-p/opt/dockerdata/mongodb/data3、docker启动 mongodockerrun-itd--namemon......
  • golang查询数据报错:closing bad idle connection: unexpected read from socket
    原因应用程序在使用驱动的有效空闲连接时候,发现数据库的连接已经失效(因为连接超过wait_timeout时间),用一个失效的连接查数据,所以报错。解决办法将sql驱动SetConnMaxLifetime和SetConnMaxIdleTime设置时间,并且小于数据库的wait_timeout时间(单位秒)。调小wait_timeout。分析......
  • javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabl
    一、问题现场二、处理方案VMoptions"-Djdk.tls.disabledAlgorithms=SSLv3,TLSv1.1,RC4,DES,MD5withRSA,DHkeySize<1024,ECkeySize<224,3DES_EDE_CBC,anon,NULL,includejdk.disabled.namedCurves"Workingdirectory$ProjectFileDir$ 三、处理结果......
  • MongoDB基础入门
    MongoDB基础入门基本概念MongoDB是一个基于分布式文件存储的非关系型数据库(NoSql),官网,中文网操作语法与JavaScript类似,容易上手,学习成本低Mongodb中有三个重要概念需要掌握数据库(database)数据库是一个数据仓库,数据库服务下可以创建很多数据库,数据库中可以存放很多集合集......