在使用Protobuf通信或者存储过程中,可能会有这样一个需求,根据PB的message名字来构建一个PB结构的实例,然后再进行反序列化。 举个例子,现在有一个PB:

1syntax = "proto3";
2option go_package = "./netmsg;netmsg";
3package netmsg;
4
5message pbPingPong
6{
7	uint32 time = 1;
8}

序列化成二进制数据后,再根据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实例。

下面直接给出源码:

 1package main
 2
 3import (
 4	"google.golang.org/protobuf/proto"
 5	"google.golang.org/protobuf/reflect/protoreflect"
 6	"google.golang.org/protobuf/reflect/protoregistry"
 7	"server/netmsg"
 8	"testing"
 9)
10
11func NewPB(message protoreflect.FullName) (proto.Message, error) {
12	name, err := protoregistry.GlobalTypes.FindMessageByName(message)
13	if err != nil {
14		return nil, err
15	}
16	return name.New().Interface(), nil
17}
18
19func TestPB(t *testing.T) {
20	pb := &netmsg.PbPingPong{
21		Time: 10,
22	}
23	data, err := proto.Marshal(pb)
24	if err != nil {
25		t.Errorf(err.Error())
26		return
27	}
28	name := proto.MessageName(pb)
29	newPB, err := NewPB(name)
30	if err != nil {
31		t.Errorf(err.Error())
32		return
33	}
34	err = proto.Unmarshal(data, newPB)
35	if err != nil {
36		t.Errorf(err.Error())
37		return
38	}
39	if newPB.(*netmsg.PbPingPong).Time != 10 {
40		t.Errorf("time should be equal")
41	}
42	t.Logf("OK")
43}

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