Protobuf⇢Go转换

这里使用一个测试文件对照说明常用结构的protobuf到golang的转换。只说明关键部分代码,详细内容请查看完整文件。示例文件在proto/test目录下。

Package

在proto文件中使用package关键字声明包名,默认转换成go中的包名与此一致,如果需要指定不一样的包名,可以使用go_package选项:

  1. package test;
  2. option go_package="test";

Message

proto中的message对应go中的struct,全部使用驼峰命名规则。嵌套定义的messageenum转换为go之后,名称变为Parent_Child结构。

示例proto:

  1. // Test 测试
  2. message Test {
  3. int32 age = 1;
  4. int64 count = 2;
  5. double money = 3;
  6. float score = 4;
  7. string name = 5;
  8. bool fat = 6;
  9. bytes char = 7;
  10. // Status 枚举状态
  11. enum Status {
  12. OK = 0;
  13. FAIL = 1;
  14. }
  15. Status status = 8;
  16. // Child 子结构
  17. message Child {
  18. string sex = 1;
  19. }
  20. Child child = 9;
  21. map<string, string> dict = 10;
  22. }

转换结果:

  1. // Status 枚举状态
  2. type Test_Status int32
  3. const (
  4. Test_OK Test_Status = 0
  5. Test_FAIL Test_Status = 1
  6. )
  7. // Test 测试
  8. type Test struct {
  9. Age int32 `protobuf:"varint,1,opt,name=age" json:"age,omitempty"`
  10. Count int64 `protobuf:"varint,2,opt,name=count" json:"count,omitempty"`
  11. Money float64 `protobuf:"fixed64,3,opt,name=money" json:"money,omitempty"`
  12. Score float32 `protobuf:"fixed32,4,opt,name=score" json:"score,omitempty"`
  13. Name string `protobuf:"bytes,5,opt,name=name" json:"name,omitempty"`
  14. Fat bool `protobuf:"varint,6,opt,name=fat" json:"fat,omitempty"`
  15. Char []byte `protobuf:"bytes,7,opt,name=char,proto3" json:"char,omitempty"`
  16. Status Test_Status `protobuf:"varint,8,opt,name=status,enum=test.Test_Status" json:"status,omitempty"`
  17. Child *Test_Child `protobuf:"bytes,9,opt,name=child" json:"child,omitempty"`
  18. Dict map[string]string `protobuf:"bytes,10,rep,name=dict" json:"dict,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
  19. }
  20. // Child 子结构
  21. type Test_Child struct {
  22. Sex string `protobuf:"bytes,1,opt,name=sex" json:"sex,omitempty"`
  23. }

除了会生成对应的结构外,还会有些工具方法,如字段的getter:

  1. func (m *Test) GetAge() int32 {
  2. if m != nil {
  3. return m.Age
  4. }
  5. return 0
  6. }

枚举类型会生成对应名称的常量,同时会有两个map方便使用:

  1. var Test_Status_name = map[int32]string{
  2. 0: "OK",
  3. 1: "FAIL",
  4. }
  5. var Test_Status_value = map[string]int32{
  6. "OK": 0,
  7. "FAIL": 1,
  8. }

Service

定义一个简单的Service,TestService有一个方法Test,接收一个Request参数,返回Response

  1. // TestService 测试服务
  2. service TestService {
  3. // Test 测试方法
  4. rpc Test(Request) returns (Response) {};
  5. }
  6. // Request 请求结构
  7. message Request {
  8. string name = 1;
  9. }
  10. // Response 响应结构
  11. message Response {
  12. string message = 1;
  13. }

转换结果:

  1. // 客户端接口
  2. type TestServiceClient interface {
  3. // Test 测试方法
  4. Test(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
  5. }
  6. // 服务端接口
  7. type TestServiceServer interface {
  8. // Test 测试方法
  9. Test(context.Context, *Request) (*Response, error)
  10. }

生成的go代码中包含该Service定义的接口,客户端接口已经自动实现了,直接供客户端使用者调用,服务端接口需要由服务提供方实现。