Go 如何使用github.com/jhump/protoreflect解析proto消息的字节数组,知道消息描述符

Go 如何使用github.com/jhump/protoreflect解析proto消息的字节数组,知道消息描述符,go,protocol-buffers,Go,Protocol Buffers,我有一个包含以下原始消息的字节片的文件 syntax = "proto3"; package main; message Address { string street = 1; string country = 2; string state = 3; } 我的消息类型描述如下: func GetProtoDescriptor()(*descriptor.DescriptorProto,错误){ return&descriptor.DescriptorProto{

我有一个包含以下原始消息的字节片的文件

syntax = "proto3";

package main;

message Address {
    string street = 1;
    string country = 2;
    string state = 3;
}
我的消息类型描述如下:

func GetProtoDescriptor()(*descriptor.DescriptorProto,错误){
return&descriptor.DescriptorProto{
名称:proto.String(“地址”),
字段:[]*descriptor.FieldDescriptorProto{
&descriptor.FieldDescriptorProto{
名称:proto.String(“street”),
JsonName:proto.String(“street”),
编号:proto.Int(1),
Label:descriptor.FieldDescriptorProto_Label_可选。Enum(),
类型:descriptor.FieldDescriptorProto_Type_STRING.Enum(),
},
&descriptor.FieldDescriptorProto{
名称:proto.String(“state”),
JsonName:proto.String(“state”),
编号:proto.Int(2),
Label:descriptor.FieldDescriptorProto_Label_可选。Enum(),
类型:descriptor.FieldDescriptorProto_Type_STRING.Enum(),
},
&descriptor.FieldDescriptorProto{
名称:proto.String(“国家”),
JsonName:proto.String(“国家”),
编号:proto.Int(2),
Label:descriptor.FieldDescriptorProto_Label_可选。Enum(),
类型:descriptor.FieldDescriptorProto_Type_STRING.Enum(),
},
},
},零
}
我想知道如何最好地使用上面的消息描述符来解析文件的内容


谢谢您的帮助。

典型的方法是使用
protoc
编译协议代码:

protoc main.proto--go_out=。
这将生成
main.pb.go
,其类型为
Address

var地址
错误:=proto.Unmarshal(字节和地址)
如果由于某种原因无法执行此操作(例如,必须使用描述符动态执行),则有一些选项。(但要复杂得多。)

  • 使用
    协议
    生成的描述符。您可以将
    protoc
    导出到描述符文件(通过
    -o
    标志)。如果这是用于RPC,请让服务器使用;然后,您可以使用该包下载服务器的描述符(可能是由
    protoc
    生成的)
  • 如果必须以编程方式创建描述符,而不是使用
    protoc
    ,我建议使用包来构造它(而不是尝试手动创建原始protos)。例如,您的原始proto是不够的,因为它们没有父级
    FileDescriptorProto
    ,父级是任何描述符层次结构的根。该生成器包可以为您处理类似的细节(例如,如果需要,它将合成父文件描述符)
  • 在任何情况下,所需的描述符都是
    desc.descriptor
    (来自软件包)。上面的提示(使用其他protoreflect子包)将返回
    desc.Descriptor
    实例。如果您只有原始描述符protos(如示例代码中所示),则需要首先使用函数将
    *descriptor.FileDescriptorProto
    转换为
    *desc.FileDescriptor

    如果您正在使用
    protoc
    及其
    -o
    选项创建描述符集文件(不要忘记
    --也要使用include_imports
    标志),您可以使用函数将其加载并转换为
    *desc.FileDescriptor
    。下面是一个例子:

    bytes, err := ioutil.ReadFile("protoset-from-protoc")
    if err != nil {
      panic(err)
    }
    var fileSet descriptor.FileDescriptorSet
    if err := proto.Unmarshal(bytes, &fileSet); err != nil {
      panic(err)
    }
    fd, err := desc.CreateFileDescriptorFromSet(&fileSet)
    if err != nil {
      panic(err)
    }
    // Now you have a *desc.FileDescriptor in `fd`
    

    一旦有了合适的描述符,就可以创建一个。然后,您可以使用
    proto#unmarshal
    函数或使用动态消息的
    unmarshal
    方法将其解组到该协议中。

    典型的方法是使用
    protoc
    编译协议到Go代码中:

    protoc main.proto--go_out=。
    
    这将生成
    main.pb.go
    ,其类型为
    Address

    var地址
    错误:=proto.Unmarshal(字节和地址)
    
    如果由于某种原因无法执行此操作(例如,必须使用描述符动态执行),则有一些选项。(但要复杂得多。)

  • 使用
    协议
    生成的描述符。您可以将
    protoc
    导出到描述符文件(通过
    -o
    标志)。如果这是用于RPC,请让服务器使用;然后,您可以使用该包下载服务器的描述符(可能是由
    protoc
    生成的)
  • 如果必须以编程方式创建描述符,而不是使用
    protoc
    ,我建议使用包来构造它(而不是尝试手动创建原始protos)。例如,您的原始proto是不够的,因为它们没有父级
    FileDescriptorProto
    ,父级是任何描述符层次结构的根。该生成器包可以为您处理类似的细节(例如,如果需要,它将合成父文件描述符)
  • 在任何情况下,所需的描述符都是
    desc.descriptor
    (来自软件包)。上面的提示(使用其他protoreflect子包)将返回
    desc.Descriptor
    实例。如果您只有原始描述符protos(如示例代码中所示),则需要首先使用函数将
    *descriptor.FileDescriptorProto
    转换为
    *desc.FileDescriptor

    如果您正在使用
    protoc
    及其
    -o
    选项创建描述符集文件(不要忘记
    --也要使用include_imports
    标志),您可以使用函数将其加载并转换为
    *desc.FileDescriptor
    。下面是一个例子:

    bytes, err := ioutil.ReadFile("protoset-from-protoc")
    if err != nil {
      panic(err)
    }
    var fileSet descriptor.FileDescriptorSet
    if err := proto.Unmarshal(bytes, &fileSet); err != nil {
      panic(err)
    }
    fd, err := desc.CreateFileDescriptorFromSet(&fileSet)
    if err != nil {
      panic(err)
    }
    // Now you have a *desc.FileDescriptor in `fd`
    
    一旦有了合适的描述符,就可以创建一个。然后,您可以使用
    proto#unmarshal
    函数或使用动态消息的
    unmarshal将其解组