Convert protobuf to struct in golang

huangapple go评论72阅读模式
英文:

Convert protobuf to struct in golang

问题

我想将proto消息转换为结构体。proto消息和结构体的定义如下:

ProtoMessage:
message Person {
  string Name = 1;
  int64 Age = 2;
  string Location = 3;
}

Human Struct:
type human struct {
	Name     string `protobuf:"Name"`
	Age      int64  `protobuf:"Age"`
	Location string `protobuf:"Location"`
}

目前我看到的唯一选项是使用protojson和json库将proto转换为JSON,然后再将JSON转换为结构体。有人可以推荐其他的转换方式吗?

英文:

I want to convert the proto Message to struct. Definitions of proto Message and struct:

ProtoMessage:
message Person {
  string Name = 1;
  int64 Age = 2;
  string Location = 3;
}

Human Struct:
type human struct {
	Name     string `protobuf:"Name"`
	Age      int64  `protobuf:"Age"`
	Location string `protobuf:"Location"`
}

Right now I see that the only option is to convert proto to JSON and JSON to struct using protojson and json library. Can someone recommend any other way of conversion?

答案1

得分: 1

protobuf编译器应该可以有效地为您完成这个任务。

从头开始,进行以下准备工作(75705541是当前的stackoverflow问题编号):

$ mkdir 75705541
$ cd 75705541
$ wget https://github.com/protocolbuffers/protobuf/releases/download/v22.2/protoc-22.2-linux-x86_64.zip
$ unzip protoc-22.2-linux-x86_64.zip
$ PATH="$(pwd)/bin:${PATH}"
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest

创建一个本地文件(ex.proto):

syntax = "proto3";

message Person {
  string Name = 1;
  int64 Age = 2;
  string Location = 3;
}

然后将其编译为Go代码:

$ protoc -I=./ --go_out=./ --go_opt=Mex.proto=this/ex ex.proto

生成的输出文件 this/ex/ex.pb.go 包含了 Person 的定义:

type Person struct {
        state         protoimpl.MessageState
        sizeCache     protoimpl.SizeCache
        unknownFields protoimpl.UnknownFields

        Name     string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"`
        Age      int64  `protobuf:"varint,2,opt,name=Age,proto3" json:"Age,omitempty"`
        Location string `protobuf:"bytes,3,opt,name=Location,proto3" json:"Location,omitempty"`
}

这几乎是您想要的结果。它有一些额外的字段,但这些字段是私有的,所以在生成的 this/ex 包之外是不可见的。

将二进制数据转换为这个结构的过程可以使用类似下面的代码实现(参考:这里):

        var data []byte = yourData // 二进制数据的字节流
        var person ex.Person
        if err := proto.Unmarshal(data, &person); err != nil {
                // 处理解码问题,查看 err。
                return err
        }
        // person 现在包含了您想要的数据。

如果您一定要有一个简化版本,您可能需要手动编辑一个。您可以从类似下面的内容开始:

$ cat this/ex/ex.pb.go | sed -n '/^type Person struct {/,/^}/p' | sed -e '/^[\t]\+[a-z].*$/d'

但是您需要编写一个函数,将 this/ex.Person 的每个导出字段复制到您的 Person 定义中。对于像 ex.Person 这样简单的类型,这相对容易,但如果您有一个嵌套的protobuf定义,这将变得复杂起来。

英文:

The protobuf compiler should effectively do this for you.

From scratch, do this prep (the 75705541 number is this present stackoverflow question):

$ mkdir 75705541
$ cd 75705541
$ wget https://github.com/protocolbuffers/protobuf/releases/download/v22.2/protoc-22.2-linux-x86_64.zip
$ unzip protoc-22.2-linux-x86_64.zip
$ PATH="$(pwd)/bin:${PATH}"
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest

Create a local file (ex.proto):

syntax = "proto3";

message Person {
  string Name = 1;
  int64 Age = 2;
  string Location = 3;
}

Then compile it to Go:

$ protoc -I=./ --go_out=./ --go_opt=Mex.proto=this/ex ex.proto

The generated output, this/ex/ex.pb.go contains this definition for Person:

type Person struct {
        state         protoimpl.MessageState
        sizeCache     protoimpl.SizeCache
        unknownFields protoimpl.UnknownFields

        Name     string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"`
        Age      int64  `protobuf:"varint,2,opt,name=Age,proto3" json:"Age,omitempty"`
        Location string `protobuf:"bytes,3,opt,name=Location,proto3" json:"Location,omitempty"`
}

which is almost what you want. It has some extra fields, but these are private so they won't be visible outside our generated "this/ex" package.

Converting from a wire format blob to this structure uses code like this:

        var data []byte = yourData // the binary blob of wire format data
        var person ex.Person
        if err := proto.Unmarshal(data, &person); err != nil {
                // handle decode problem, see err.
                return err
        }
        // person now holds the data you want.

If you must have a simple version, you will likely have to hand edit one. You could start with something like this:

$ cat this/ex/ex.pb.go | sed -n '/^type Person struct {/,/^}/p' | sed -e '/^[\t]\+[a-z].*$/d'

but you will need to write a function to import this by copying each of the exported fields from this/ex.Person to your Person definition. This is relatively easy for a simple type like ex.Person, but it will get complicated if you have a nested protobuf definition.

huangapple
  • 本文由 发表于 2023年3月11日 22:15:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/75705541.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定