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,
},
},
}