go语言中protobuf使用message名字构建PB实例

发布于:2024-05-15 ⋅ 阅读:(26) ⋅ 点赞:(0)

在使用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")
}

如果对你有帮助,欢迎点赞收藏!


网站公告

今日签到

点亮在社区的每一天
去签到