go语言中protobuf使用message名字构建PB实例
在使用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}
如果对你有帮助,欢迎点赞收藏!
- 原文作者:Witton
- 原文链接:https://wittonbell.github.io/posts/2024/2024-05-15-go语言中protobuf使用message名字构建PB实例/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。