gRPC 中的泛型

gRPC generic type in golang

Posted by alovn on August 8, 2019

JAVA、C#中一般都会用泛型处理一些相识结构的数据,而 gRPC 是用 protobuf 作为数据传输格式的,那么 protobuf 中有没有泛型呢?

一番探索后了解到protbuf中有个 Any 类型, 可以用它来实现泛型的效果,还有个Value类型也可以实现类似效果。

在来看下它们各自是怎么定义的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// any 定义在 any.proto 中
import "google/protobuf/any.proto";
message Any {
  string type_url = 1;
  bytes value = 2;
}

// value 定义在 struct.proto 中
import "google/protobuf/struct.proto";
message Value {
  oneof kind { //最多同时只能设置一个字段
    NullValue null_value = 1;
    double number_value = 2;
    string string_value = 3;
    bool bool_value = 4;
    Struct struct_value = 5;
    ListValue list_value = 6;
  }
}

Any

Any: 包含一个任意序列化的bytes类型的消息,以及一个type_url,该URL充当该消息的全局唯一标识符并解析为该消息的类型。默认类型URL格式是:

1
type.googleapis.com/packagename.messagename.

要使用Any类型,首先需要导入google/protobuf/any.proto. 通过 ptypes.MarshalAny(marshal) 将定义的消息进行编码 通过 ptypes.UnmarshalAny(any, unmarshal) 对已经编码的消息进行反编码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//部分proto
import "google/protobuf/any.proto";
import "google/protobuf/struct.proto";

message CommonResponse {
    int32 err = 1;
    string msg = 2;
    google.protobuf.Any data_any = 3;
    google.protobuf.Value data_value = 4;
}

message LoginResult {
    string open_id = 1;
    string session_key = 2;
}
1
2
3
4
5
6
7
8
9
10
11
//序列化
anyResult := &pb.LoginResult{
    OpenId:     "openid--any",
    SessionKey: "sessionkey-any",
}
ret.DataAny, _ = ptypes.MarshalAny(anyResult)

//反序列化
var result pb.LoginResult
_ = ptypes.UnmarshalAny(r.DataAny, &result)
fmt.Printf("result:%+v", result)

Value

Value: 一般可以用来表示动态的类型,它可以是 NullValue、number、string、bool、Struct 或者 ListValue,不过它是用oneof定义的,也就是说最多同时只能设置一个字段。

将 struct 转为 Value 类型:

1
2
3
4
5
6
7
8
import "github.com/golang/protobuf/ptypes/struct"
&types.Value{
    Kind: &types.Value_StructValue{
        StructValue: &types.Struct{
            Fields: fields,
        },
    },
}

示例代码

官方文档