Protobuf⇢Go转换
2021.07

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

Package

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

package test;
option go_package="test";

Message

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

// Test 测试
message Test {
    int32 age = 1;
    int64 count = 2;
    double money = 3;
    float score = 4;
    string name = 5;
    bool fat = 6;
    bytes char = 7;
    // Status 枚举状态
    enum Status {
        OK = 0;
        FAIL = 1;
    }
    Status status = 8;
    // Child 子结构
    message Child {
        string sex = 1;
    }
    Child child = 9;
    map dict = 10;
}

转换结果:

// Status 枚举状态
type Test_Status int32

const (
    Test_OK   Test_Status = 0
    Test_FAIL Test_Status = 1
)

// Test 测试
type Test struct {
    Age    int32       `protobuf:"varint,1,opt,name=age" json:"age,omitempty"`
    Count  int64       `protobuf:"varint,2,opt,name=count" json:"count,omitempty"`
    Money  float64     `protobuf:"fixed64,3,opt,name=money" json:"money,omitempty"`
    Score  float32     `protobuf:"fixed32,4,opt,name=score" json:"score,omitempty"`
    Name   string      `protobuf:"bytes,5,opt,name=name" json:"name,omitempty"`
    Fat    bool        `protobuf:"varint,6,opt,name=fat" json:"fat,omitempty"`
    Char   []byte      `protobuf:"bytes,7,opt,name=char,proto3" json:"char,omitempty"`
    Status Test_Status `protobuf:"varint,8,opt,name=status,enum=test.Test_Status" json:"status,omitempty"`
    Child  *Test_Child `protobuf:"bytes,9,opt,name=child" json:"child,omitempty"`
    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"`
}

// Child 子结构
type Test_Child struct {
    Sex string `protobuf:"bytes,1,opt,name=sex" json:"sex,omitempty"`
}

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

func (m *Test) GetAge() int32 {
    if m != nil {
        return m.Age
    }
    return 0
}

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

var Test_Status_name = map[int32]string{
    0: "OK",
    1: "FAIL",
}
var Test_Status_value = map[string]int32{
    "OK":   0,
    "FAIL": 1,
}

Service

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

// TestService 测试服务
service TestService {
    // Test 测试方法
    rpc Test(Request) returns (Response) {};
}

// Request 请求结构
message Request {
    string name = 1;
}

// Response 响应结构
message Response {
    string message = 1;
}

转换结果:

// 客户端接口
type TestServiceClient interface {
    // Test 测试方法
    Test(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
}

// 服务端接口
type TestServiceServer interface {
    // Test 测试方法
    Test(context.Context, *Request) (*Response, error)
}

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

Share