proto2 extensions 官网指导说明:
https://developers.google.com/protocol-buffers/docs/proto#extensions
定义:
https://github.com/golang/protobuf/blob/4846b58453b3708320bdb524f25cc5a1d9cda4d4/internal/testprotos/proto2_proto/test.proto#L266
使用方法:
https://github.com/golang/protobuf/blob/master/proto/extensions_test.go
本文重点说明proto3,但proto3也是在proto2的基础上展开的,在理解以上链接内容可以继续向下阅读。
proto3 不支持extension,只支持option, option传值设置:
https://developers.google.com/protocol-buffers/docs/proto3#options
具体option可以分为:
FileOptions
MessageOptions
FieldOptions
OneofOptions
EnumOptions
EnumValueOptions
ServiceOptions
MethodOptions
UninterpretedOption
其字段定义见:
https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/descriptor.proto
官网也有对应使用测试:
https://github.com/protocolbuffers/protobuf/blob/master/csharp/protos/unittest_custom_options_proto3.proto
test.proto:
syntax = "proto3";
import "google/protobuf/descriptor.proto";
import "google/protobuf/any.proto";
extend google.protobuf.FileOptions {
uint64 file_opt1 = 1000;
}
message mymessage{
int32 x = 10;
}
extend google.protobuf.MessageOptions {
mymessage mymsg = 1000 ;
}
extend google.protobuf.FieldOptions {
string field_opt1 = 1000;
string field_opt2 = 1001;
mymessage field_opt3 = 1002;
}
extend google.protobuf.OneofOptions {
int32 oneof_opt1 = 1000;
}
extend google.protobuf.EnumOptions {
int32 enum_opt1 = 1000;
}
extend google.protobuf.EnumValueOptions {
int32 enum_value_opt1 = 1000;
}
extend google.protobuf.ServiceOptions {
sint64 service_opt1 = 1000;
}
option (file_opt1) = 1;
message usemymessage{
option(mymsg) = {x:1} ;
string field1 = 1 [(field_opt1)="field1", (field_opt2)="field1"];
string field2 = 2 [(field_opt3) = {
x: 100;
}];
oneof AnOneof{
option (oneof_opt1) = 100;
int32 oneofint = 3;
string oneofstring = 4;
}
enum AnEnum {
option (enum_opt1) = 100;
ANENUM_UNSPECIFIED = 0;
ANENUM_VAL1 = 1;
ANENUM_VAL2 = 2 [(enum_value_opt1) = 100];
}
int32 test = 20;
repeated google.protobuf.Any details = 21;
}
message usemymessagenonoption{
string field1 = 1;
string field2 = 2;
oneof AnOneof{
int32 oneofint = 3;
string oneofstring = 4;
}
enum AnEnum {
ANENUM_UNSPECIFIED = 0;
ANENUM_VAL1 = 1;
ANENUM_VAL2 = 2;
}
int32 test = 20;
repeated google.protobuf.Any details = 21;
}
为了方便测试,下载了https://github.com/golang/protobuf,到proto文件家下新建test文件
把test.proto放入test文件夹内,编译命令 protoc --go_out=. *.proto 生成test.pb.go文件
编译中发现:
string field1 = 1 [(field_opt1)="field1", (field_opt2)="field1"]; //field_opt1必须加括号
extend google.protobuf.FileOptions {
uint64 file_opt1 = 1000 [default = 100];
}
这样编译时会报Explicit default values are not allowed in proto3错,[default = 100]要删除
然后到proto/extensions_test.go 文件中加入以下测试代码:
func TestProtoOption(t *testing.T) {
usm := &test.Usemymessage{
Field1: "usm",
Field2: "usm",
}
usmnonopt := &test.Usemymessagenonoption{
Field1: "usm",
Field2: "usm",
}
usmf, usmd := descriptor.ForMessage(usm)
_, usmnonoptd := descriptor.ForMessage(usmnonopt)
//FileOptions
if v, err := proto.GetExtension(usmf.Options, test.E_FileOpt1); err == nil {
t.Logf("GetExtensions(usmf.Options, test.E_FileOpt1) file_opt1:%d", *(v.(*uint64)))
} else {
t.Fatalf("GetExtensions(usmf.Options, test.E_FileOpt1) failed: %v", err)
}
/*output:
GetExtensions(usmf.Options, test.E_FileOpt1) file_opt1:1
*/
//MessageOptions
if _, err := proto.GetExtension(usmnonoptd.Options, test.E_Mymsg); err == nil {
t.Fatalf("GetExtension(usmd.Options, test.E_Mymsg) succ")
} else {
if err := proto.SetExtension(usmnonoptd.Options, test.E_Mymsg, &test.Mymessage{X: 100}); err != nil {
t.Logf("Usemymessagenonoption can't SetExtension and GetExtension")
}
}
if v, err := proto.GetExtension(usmd.Options, test.E_Mymsg); err == nil {
t.Logf("GetExtension(usmd.Options, test.E_Mymsg) mymsg default:%v", *(v.(*test.Mymessage)))
setmymsg := &test.Mymessage{X: 100}
if err := proto.SetExtension(usmd.Options, test.E_Mymsg, setmymsg); err == nil {
if v1, err1 := proto.GetExtension(usmd.Options, test.E_Mymsg); err1 == nil {
t.Logf("GetExtension(usmd.Options, test.E_Mymsg) mymsg after SetExtension:%v", *(v1.(*test.Mymessage)))
}
}
} else {
t.Fatalf("GetExtension(usmd.Options, test.E_Mymsg) failed: %v", err)
}
/*output:
Usemymessagenonoption can't SetExtension and GetExtension
GetExtension(usmd.Options, test.E_Mymsg) mymsg default:{1 {} [] 0}
GetExtension(usmd.Options, test.E_Mymsg) mymsg after SetExtension:{100 {} [] 0}
*/
//FieldOptions
for _, field := range usmd.Field {
if *(field.Name) == "field1" {
if v, err := proto.GetExtensions(field.Options, []*proto.ExtensionDesc{test.E_FieldOpt1, test.E_FieldOpt2}); err == nil {
t.Logf("field1 field_opt1 default:%v, field1 field_opt1 default:%v", *(v[0].(*string)), *(v[1].(*string)))
} else {
t.Fatalf("GetExtension(usmd.Options, []*proto.ExtensionDesc{test.E_FieldOpt1, test.E_FieldOpt2}) failed: %v", err)
}
}
if *(field.Name) == "field2" {
if v, err := proto.GetExtension(field.Options, test.E_FieldOpt3); err == nil {
t.Logf("field2 field_opt3 default:%v", *(v.(*test.Mymessage)))
} else {
t.Fatalf("GetExtensions(field.Options, test.E_FieldOpt3) failed: %v", err)
}
}
}
/*output:
field1 field_opt1 default:field1, field1 field_opt1 default:field1
field2 field_opt3 default:{100 {} [] 0}
*/
}