在使用Protobuf通信或者存储过程中,可能会有这样一个需求,根据PB的message名字来构建一个PB结构的实例,然后再进行反序列化。
举个例子,现在有一个PB:
syntax = "proto3";
option go_package = "./netmsg;netmsg";
package netmsg;
message pbPingPong
{
uint32 time = 1;
}
序列化成二进制数据后,再根据message名字netmsg.pbPingPong
来创建一个PB实例,从而可以对之前序列化的二进制数据进行反序列化。
所有的PB结构类型,都在protoregistry.GlobalTypes
有根据名字注册,注意是全名,即包含包路径,比如前面的pbPingPong
全名为netmsg.pbPingPong
,可以使用proto.MessageName(m Message) protoreflect.FullName
函数取得。有了全名,就可以使用protoregistry.GlobalTypes.FindMessageByName(message protoreflect.FullName) (protoreflect.MessageType, error)
获取PB类型,再根据类型构建出PB实例。
下面直接给出源码:
package main
import (
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"server/netmsg"
"testing"
)
func NewPB(message protoreflect.FullName) (proto.Message, error) {
name, err := protoregistry.GlobalTypes.FindMessageByName(message)
if err != nil {
return nil, err
}
return name.New().Interface(), nil
}
func TestPB(t *testing.T) {
pb := &netmsg.PbPingPong{
Time: 10,
}
data, err := proto.Marshal(pb)
if err != nil {
t.Errorf(err.Error())
return
}
name := proto.MessageName(pb)
newPB, err := NewPB(name)
if err != nil {
t.Errorf(err.Error())
return
}
err = proto.Unmarshal(data, newPB)
if err != nil {
t.Errorf(err.Error())
return
}
if newPB.(*netmsg.PbPingPong).Time != 10 {
t.Errorf("time should be equal")
}
t.Logf("OK")
}
如果对你有帮助,欢迎点赞收藏!