Golang的序列化-ProtoBuf篇
作者:尹正傑
版權聲明:原創作品,謝絕轉載!否則將追究法律責任。
一.protobuf概述
Protobuf是Protocol Buffers的簡稱,它是Google公司用C語言(因此很多語法借鑒C語法特性)開發的一種數據描述語言,是一種輕便高效的結構化數據存儲格式,可以用於結構化數據串行化,或者說序列化。 它很適合做數據存儲或RPC數據交換格式。 可用於通訊協議、數據存儲等領域的語言無關、平台無關、可擴展的序列化結構數據格式。目前提供了C++、Java、Python三種語言的API,其它語言需要安裝相關插件才能使用。 Protobuf剛開源時的定位類似於XML、JSON等數據描述語言,通過附帶工具生成代碼並實現將結構化數據序列化的功能。 這里我們更關注的是Protobuf作為接口規范的描述語言,可以作為設計安全的跨語言RPC接口的基礎工具。需要了解以下兩點 1>.protobuf是類似與json一樣的數據描述語言(數據格式); 2>.protobuf非常適合於RPC數據交換格式; 接着我們來看一下protobuf的優勢和劣勢: 優勢: 1>序列化后體積相比Json和XML很小,適合網絡傳輸 2>支持跨平台多語言 3>消息格式升級和兼容性還不錯 4>序列化反序列化速度很快,快於Json的處理速度 劣勢: 1>應用不夠廣(相比xml和json) 2>二進制格式導致可讀性差 3>缺乏自描述 博主推薦閱讀: https://developers.google.cn/protocol-buffers/docs/gotutorial
二.protobuf安裝
1>.下載protobuf軟件包
博主推薦閱讀: https://github.com/protocolbuffers/protobuf/releases
2>.配置環境變量
3>.安裝Go的編譯插件
執行以下命令安裝插件:
go get -u github.com/golang/protobuf/protoc-gen-go
如下圖所示,安裝成功后會在%GOPATH%\bin目錄生成一個編譯工具"protoc-gen-go.exe"
三.protobuf的簡單語法
1>.參考文檔
博主推薦閱讀: https://developers.google.com/protocol-buffers/docs/reference/go-generated
2>.編寫簡單的protobuf案例(文件名后綴以".proto"結尾)
//protobuf默認支持的版本是2.x,現在一般使用3.x版本,所以需要手動指定版本號,如果不這樣做,協議緩沖區編譯器將假定正在使用proto2。這也必須是文件的第一個非空的非注釋行。 syntax = "proto3"; //指定包名,package關鍵字指明當前是mypb包生(成go文件之后和Go的包名保持一致,但是如果定義了"option go_package"參數,則package的參數自動失效) package mypb; //.proto文件應包含一個go_package選項,用於指定包含所生成代碼的Go軟件包的完整導入路徑(最后一次"bar"就是生成go文件的包名),官方在未來的發行版本會支持喲; option go_package ="example.com/foo/bar"; /* 通過message關鍵定義傳輸數據的格式,,類似於go語言中的結構體,是包含一系列類 型數據的集合。 許多標准的簡單數據類型都可以作為字段類型,包括 bool , int32 , float , double ,和 string 。也可以使用其他message類型作為字段類型。 */ message People{ /* 注意哈,這里的"1"表示字段是1,類似於數據庫中表的主鍵id等於1,主鍵不能重復,標識位數據不能重復。該成員編碼時用1代替名字。 我們知道,在json中是通過成員的名字來綁定對應的數據,但是Protobuf編碼卻是通過成員的唯一編號來綁定對應的數據。 綜上所述,因此Protobuf編碼后數據的體積會比較小,能夠快速傳輸,缺點是不利於閱讀。 */ string name = 1; //需要注意的是,標識為不能使用19000-19999(系統預留位) int32 age = 2; //結構體嵌套,比如我們嵌套一個Student結構體 Student s = 3; //使用數組 repeated string phone = 4; } /* message的格式說明如下: 消息由至少一個字段組合而成,類似於Go語言中的結構體,每個字段都有一定的格式 (字段修飾符)數據類型 字段名稱 = 唯一的編號標簽值; 唯一的編號標簽: 代表每個字段的一個唯一的編號標簽,在同一個消息里不可以重復。這些編號標簽用與在消息二進制格式中標識你的字段,並且消息一旦定義就不能更改。需要說明的是標簽在1到15范圍的采用一個字節進行編碼,所以通常將標簽1到15用於頻繁發生的消 息字段。 編號標簽大小的范圍是1到2的29次。19000-19999是官方預留的值,不能使用。 注釋格式: 向.proto文件添加注釋,可以使用C/C++/java/Go風格的雙斜杠或者段落注釋語法格式。 message常見的數據類型與go中類型對比: .proto類型 Go類型 介紹 double float64 64位浮點數 float float32 32位浮點數 int32 int32 使用可變長度編碼。編碼負數效率低下——如果你的字段可能有負值, 請改用sint32。 int64 int64 使用可變長度編碼。編碼負數效率低下——如果你的字段可能有負值, 請改用sint64。 uint32 uint32 使用可變長度編碼。 uint64 uint64 使用可變長度編碼。 sint32 int32 使用可變長度編碼。符號整型值。這些比常規int32s編碼負數更有效。 sint64 int64 使用可變長度編碼。符號整型值。這些比常規int64s編碼負數更有效。 fixed32 uint32 總是四字節。如果值通常大於228,則比uint 32更有效 fixed64 uint64 總是八字節。如果值通常大於256,則比uint64更有效 sfixed32 int32 總是四字節。 sfixed64 int64 總是八字節。 bool bool 布爾類型 string string 字符串必須始終包含UTF - 8編碼或7位ASCII文本 bytes []byte 可以包含任意字節序列 */ message Student{ string name = 1; int32 age = 5; }
3>.基於protobuf文件進行編譯生成對應的go文件
protoc --go_out=. demo.proto

//protobuf默認支持的版本是2.x,現在一般使用3.x版本,所以需要手動指定版本號,如果不這樣做,協議緩沖區編譯器將假定正在使用proto2。這也必須是文件的第一個非空的非注釋行。 // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.21.0 // protoc v3.11.4 // source: demo.proto //指定包名,package關鍵字指明當前是mypb包生(成go文件之后和Go的包名保持一致,但是如果定義了"option go_package"參數,則package的參數失效) package bar import ( proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) // This is a compile-time assertion that a sufficiently up-to-date version // of the legacy proto package is being used. const _ = proto.ProtoPackageIsVersion4 // //通過message關鍵定義傳輸數據的格式,,類似於go語言中的結構體,是包含一系列類 型數據的集合。 //許多標准的簡單數據類型都可以作為字段類型,包括 bool , int32 , float , double ,和 string 。也可以使用其他message類型作為字段類型。 type People struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // //注意哈,這里的"1"表示字段是1,類似於數據庫中表的主鍵id等於1,主鍵不能重復,標識位數據不能重復。該成員編碼時用1代替名字。 //我們知道,在json中是通過成員的名字來綁定對應的數據,但是Protobuf編碼卻是通過成員的唯一編號來綁定對應的數據。 //綜上所述,因此Protobuf編碼后數據的體積會比較小,能夠快速傳輸,缺點是不利於閱讀。 Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` //需要注意的是,標識為不能使用19000-19999(系統預留位) Age int32 `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"` //結構體嵌套,比如我們嵌套一個Student結構體 S *Student `protobuf:"bytes,3,opt,name=s,proto3" json:"s,omitempty"` //使用數組 Phone []string `protobuf:"bytes,4,rep,name=phone,proto3" json:"phone,omitempty"` } func (x *People) Reset() { *x = People{} if protoimpl.UnsafeEnabled { mi := &file_demo_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *People) String() string { return protoimpl.X.MessageStringOf(x) } func (*People) ProtoMessage() {} func (x *People) ProtoReflect() protoreflect.Message { mi := &file_demo_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use People.ProtoReflect.Descriptor instead. func (*People) Descriptor() ([]byte, []int) { return file_demo_proto_rawDescGZIP(), []int{0} } func (x *People) GetName() string { if x != nil { return x.Name } return "" } func (x *People) GetAge() int32 { if x != nil { return x.Age } return 0 } func (x *People) GetS() *Student { if x != nil { return x.S } return nil } func (x *People) GetPhone() []string { if x != nil { return x.Phone } return nil } // //message的格式說明如下: //消息由至少一個字段組合而成,類似於Go語言中的結構體,每個字段都有一定的格式 //(字段修飾符)數據類型 字段名稱 = 唯一的編號標簽值; // //唯一的編號標簽: //代表每個字段的一個唯一的編號標簽,在同一個消息里不可以重復。這些編號標簽用與在消息二進制格式中標識你的字段,並且消息一旦定義就不能更改。需要說明的是標簽在1到15范圍的采用一個字節進行編碼,所以通常將標簽1到15用於頻繁發生的消 息字段。 //編號標簽大小的范圍是1到2的29次。19000-19999是官方預留的值,不能使用。 // //注釋格式: //向.proto文件添加注釋,可以使用C/C++/java/Go風格的雙斜杠或者段落注釋語法格式。 // //message常見的數據類型與go中類型對比: //.proto類型 Go類型 介紹 //double float64 64位浮點數 //float float32 32位浮點數 //int32 int32 使用可變長度編碼。編碼負數效率低下——如果你的字段可能有負值, 請改用sint32。 //int64 int64 使用可變長度編碼。編碼負數效率低下——如果你的字段可能有負值, 請改用sint64。 //uint32 uint32 使用可變長度編碼。 //uint64 uint64 使用可變長度編碼。 //sint32 int32 使用可變長度編碼。符號整型值。這些比常規int32s編碼負數更有效。 //sint64 int64 使用可變長度編碼。符號整型值。這些比常規int64s編碼負數更有效。 //fixed32 uint32 總是四字節。如果值通常大於228,則比uint 32更有效 //fixed64 uint64 總是八字節。如果值通常大於256,則比uint64更有效 //sfixed32 int32 總是四字節。 //sfixed64 int64 總是八字節。 //bool bool 布爾類型 //string string 字符串必須始終包含UTF - 8編碼或7位ASCII文本 //bytes []byte 可以包含任意字節序列 type Student struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Age int32 `protobuf:"varint,5,opt,name=age,proto3" json:"age,omitempty"` } func (x *Student) Reset() { *x = Student{} if protoimpl.UnsafeEnabled { mi := &file_demo_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Student) String() string { return protoimpl.X.MessageStringOf(x) } func (*Student) ProtoMessage() {} func (x *Student) ProtoReflect() protoreflect.Message { mi := &file_demo_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Student.ProtoReflect.Descriptor instead. func (*Student) Descriptor() ([]byte, []int) { return file_demo_proto_rawDescGZIP(), []int{1} } func (x *Student) GetName() string { if x != nil { return x.Name } return "" } func (x *Student) GetAge() int32 { if x != nil { return x.Age } return 0 } var File_demo_proto protoreflect.FileDescriptor var file_demo_proto_rawDesc = []byte{ 0x0a, 0x0a, 0x64, 0x65, 0x6d, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x6d, 0x79, 0x70, 0x62, 0x22, 0x61, 0x0a, 0x06, 0x50, 0x65, 0x6f, 0x70, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x01, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6d, 0x79, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x01, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x22, 0x2f, 0x0a, 0x07, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x67, 0x65, 0x42, 0x15, 0x5a, 0x13, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6f, 0x6f, 0x2f, 0x62, 0x61, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_demo_proto_rawDescOnce sync.Once file_demo_proto_rawDescData = file_demo_proto_rawDesc ) func file_demo_proto_rawDescGZIP() []byte { file_demo_proto_rawDescOnce.Do(func() { file_demo_proto_rawDescData = protoimpl.X.CompressGZIP(file_demo_proto_rawDescData) }) return file_demo_proto_rawDescData } var file_demo_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_demo_proto_goTypes = []interface{}{ (*People)(nil), // 0: mypb.People (*Student)(nil), // 1: mypb.Student } var file_demo_proto_depIdxs = []int32{ 1, // 0: mypb.People.s:type_name -> mypb.Student 1, // [1:1] is the sub-list for method output_type 1, // [1:1] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name 1, // [1:1] is the sub-list for extension extendee 0, // [0:1] is the sub-list for field type_name } func init() { file_demo_proto_init() } func file_demo_proto_init() { if File_demo_proto != nil { return } if !protoimpl.UnsafeEnabled { file_demo_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*People); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_demo_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Student); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_demo_proto_rawDesc, NumEnums: 0, NumMessages: 2, NumExtensions: 0, NumServices: 0, }, GoTypes: file_demo_proto_goTypes, DependencyIndexes: file_demo_proto_depIdxs, MessageInfos: file_demo_proto_msgTypes, }.Build() File_demo_proto = out.File file_demo_proto_rawDesc = nil file_demo_proto_goTypes = nil file_demo_proto_depIdxs = nil }
四.protobuf的高級用法
1>.message嵌套
//protobuf默認支持的版本是2.x,現在一般使用3.x版本,所以需要手動指定版本號,如果不這樣做,協議緩沖區編譯器將假定正在使用proto2。這也必須是文件的第一個非空的非注釋行。 syntax = "proto3"; //.proto文件應包含一個go_package選項,用於指定包含所生成代碼的Go軟件包的完整導入路徑(最后一次"bar"就是生成go文件的包名),官方在未來的發行版本會支持喲; option go_package ="example.com/foo/bar"; message Teacher{ //姓名 string name = 1; //年齡 int32 age = 2 ; //地址 string address = 3; //定義一個message message PhoneNumber{ string number = 1; int64 type = 2; } //使用咱們定義的messge PhoneNumber phone = 4 ; }

//protobuf默認支持的版本是2.x,現在一般使用3.x版本,所以需要手動指定版本號,如果不這樣做,協議緩沖區編譯器將假定正在使用proto2。這也必須是文件的第一個非空的非注釋行。 // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.21.0 // protoc v3.11.4 // source: demo2.proto package bar import ( proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) // This is a compile-time assertion that a sufficiently up-to-date version // of the legacy proto package is being used. const _ = proto.ProtoPackageIsVersion4 type Teacher struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields //姓名 Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` //年齡 Age int32 `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"` //地址 Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` //使用咱們定義的messge Phone *Teacher_PhoneNumber `protobuf:"bytes,4,opt,name=phone,proto3" json:"phone,omitempty"` } func (x *Teacher) Reset() { *x = Teacher{} if protoimpl.UnsafeEnabled { mi := &file_demo2_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Teacher) String() string { return protoimpl.X.MessageStringOf(x) } func (*Teacher) ProtoMessage() {} func (x *Teacher) ProtoReflect() protoreflect.Message { mi := &file_demo2_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Teacher.ProtoReflect.Descriptor instead. func (*Teacher) Descriptor() ([]byte, []int) { return file_demo2_proto_rawDescGZIP(), []int{0} } func (x *Teacher) GetName() string { if x != nil { return x.Name } return "" } func (x *Teacher) GetAge() int32 { if x != nil { return x.Age } return 0 } func (x *Teacher) GetAddress() string { if x != nil { return x.Address } return "" } func (x *Teacher) GetPhone() *Teacher_PhoneNumber { if x != nil { return x.Phone } return nil } //定義一個message type Teacher_PhoneNumber struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Number string `protobuf:"bytes,1,opt,name=number,proto3" json:"number,omitempty"` Type int64 `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"` } func (x *Teacher_PhoneNumber) Reset() { *x = Teacher_PhoneNumber{} if protoimpl.UnsafeEnabled { mi := &file_demo2_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Teacher_PhoneNumber) String() string { return protoimpl.X.MessageStringOf(x) } func (*Teacher_PhoneNumber) ProtoMessage() {} func (x *Teacher_PhoneNumber) ProtoReflect() protoreflect.Message { mi := &file_demo2_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Teacher_PhoneNumber.ProtoReflect.Descriptor instead. func (*Teacher_PhoneNumber) Descriptor() ([]byte, []int) { return file_demo2_proto_rawDescGZIP(), []int{0, 0} } func (x *Teacher_PhoneNumber) GetNumber() string { if x != nil { return x.Number } return "" } func (x *Teacher_PhoneNumber) GetType() int64 { if x != nil { return x.Type } return 0 } var File_demo2_proto protoreflect.FileDescriptor var file_demo2_proto_rawDesc = []byte{ 0x0a, 0x0b, 0x64, 0x65, 0x6d, 0x6f, 0x32, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb0, 0x01, 0x0a, 0x07, 0x54, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x54, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x1a, 0x39, 0x0a, 0x0b, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x42, 0x15, 0x5a, 0x13, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6f, 0x6f, 0x2f, 0x62, 0x61, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_demo2_proto_rawDescOnce sync.Once file_demo2_proto_rawDescData = file_demo2_proto_rawDesc ) func file_demo2_proto_rawDescGZIP() []byte { file_demo2_proto_rawDescOnce.Do(func() { file_demo2_proto_rawDescData = protoimpl.X.CompressGZIP(file_demo2_proto_rawDescData) }) return file_demo2_proto_rawDescData } var file_demo2_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_demo2_proto_goTypes = []interface{}{ (*Teacher)(nil), // 0: Teacher (*Teacher_PhoneNumber)(nil), // 1: Teacher.PhoneNumber } var file_demo2_proto_depIdxs = []int32{ 1, // 0: Teacher.phone:type_name -> Teacher.PhoneNumber 1, // [1:1] is the sub-list for method output_type 1, // [1:1] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name 1, // [1:1] is the sub-list for extension extendee 0, // [0:1] is the sub-list for field type_name } func init() { file_demo2_proto_init() } func file_demo2_proto_init() { if File_demo2_proto != nil { return } if !protoimpl.UnsafeEnabled { file_demo2_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Teacher); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_demo2_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Teacher_PhoneNumber); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_demo2_proto_rawDesc, NumEnums: 0, NumMessages: 2, NumExtensions: 0, NumServices: 0, }, GoTypes: file_demo2_proto_goTypes, DependencyIndexes: file_demo2_proto_depIdxs, MessageInfos: file_demo2_proto_msgTypes, }.Build() File_demo2_proto = out.File file_demo2_proto_rawDesc = nil file_demo2_proto_goTypes = nil file_demo2_proto_depIdxs = nil }
2>.repeated關鍵字
//protobuf默認支持的版本是2.x,現在一般使用3.x版本,所以需要手動指定版本號,如果不這樣做,協議緩沖區編譯器將假定正在使用proto2。這也必須是文件的第一個非空的非注釋行。 syntax = "proto3"; //.proto文件應包含一個go_package選項,用於指定包含所生成代碼的Go軟件包的完整導入路徑(最后一次"bar"就是生成go文件的包名),官方在未來的發行版本會支持喲; option go_package ="example.com/foo/bar"; message Teacher{ //姓名 string name = 1; //年齡 int32 age = 2 ; //地址 string address = 3; //定義一個message message PhoneNumber{ string number = 1; int64 type = 2; } //repeadted關鍵字類似與go中的切片,編譯之后對應的也是go的切片 repeated PhoneNumber phone = 4 ; }

//protobuf默認支持的版本是2.x,現在一般使用3.x版本,所以需要手動指定版本號,如果不這樣做,協議緩沖區編譯器將假定正在使用proto2。這也必須是文件的第一個非空的非注釋行。 // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.21.0 // protoc v3.11.4 // source: demo3.proto package bar import ( proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) // This is a compile-time assertion that a sufficiently up-to-date version // of the legacy proto package is being used. const _ = proto.ProtoPackageIsVersion4 type Teacher struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields //姓名 Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` //年齡 Age int32 `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"` //地址 Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` //repeadted關鍵字類似與go中的切片,編譯之后對應的也是go的切片 Phone []*Teacher_PhoneNumber `protobuf:"bytes,4,rep,name=phone,proto3" json:"phone,omitempty"` } func (x *Teacher) Reset() { *x = Teacher{} if protoimpl.UnsafeEnabled { mi := &file_demo3_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Teacher) String() string { return protoimpl.X.MessageStringOf(x) } func (*Teacher) ProtoMessage() {} func (x *Teacher) ProtoReflect() protoreflect.Message { mi := &file_demo3_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Teacher.ProtoReflect.Descriptor instead. func (*Teacher) Descriptor() ([]byte, []int) { return file_demo3_proto_rawDescGZIP(), []int{0} } func (x *Teacher) GetName() string { if x != nil { return x.Name } return "" } func (x *Teacher) GetAge() int32 { if x != nil { return x.Age } return 0 } func (x *Teacher) GetAddress() string { if x != nil { return x.Address } return "" } func (x *Teacher) GetPhone() []*Teacher_PhoneNumber { if x != nil { return x.Phone } return nil } //定義一個message type Teacher_PhoneNumber struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Number string `protobuf:"bytes,1,opt,name=number,proto3" json:"number,omitempty"` Type int64 `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"` } func (x *Teacher_PhoneNumber) Reset() { *x = Teacher_PhoneNumber{} if protoimpl.UnsafeEnabled { mi := &file_demo3_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Teacher_PhoneNumber) String() string { return protoimpl.X.MessageStringOf(x) } func (*Teacher_PhoneNumber) ProtoMessage() {} func (x *Teacher_PhoneNumber) ProtoReflect() protoreflect.Message { mi := &file_demo3_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Teacher_PhoneNumber.ProtoReflect.Descriptor instead. func (*Teacher_PhoneNumber) Descriptor() ([]byte, []int) { return file_demo3_proto_rawDescGZIP(), []int{0, 0} } func (x *Teacher_PhoneNumber) GetNumber() string { if x != nil { return x.Number } return "" } func (x *Teacher_PhoneNumber) GetType() int64 { if x != nil { return x.Type } return 0 } var File_demo3_proto protoreflect.FileDescriptor var file_demo3_proto_rawDesc = []byte{ 0x0a, 0x0b, 0x64, 0x65, 0x6d, 0x6f, 0x33, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb0, 0x01, 0x0a, 0x07, 0x54, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x54, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x1a, 0x39, 0x0a, 0x0b, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x42, 0x15, 0x5a, 0x13, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6f, 0x6f, 0x2f, 0x62, 0x61, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_demo3_proto_rawDescOnce sync.Once file_demo3_proto_rawDescData = file_demo3_proto_rawDesc ) func file_demo3_proto_rawDescGZIP() []byte { file_demo3_proto_rawDescOnce.Do(func() { file_demo3_proto_rawDescData = protoimpl.X.CompressGZIP(file_demo3_proto_rawDescData) }) return file_demo3_proto_rawDescData } var file_demo3_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_demo3_proto_goTypes = []interface{}{ (*Teacher)(nil), // 0: Teacher (*Teacher_PhoneNumber)(nil), // 1: Teacher.PhoneNumber } var file_demo3_proto_depIdxs = []int32{ 1, // 0: Teacher.phone:type_name -> Teacher.PhoneNumber 1, // [1:1] is the sub-list for method output_type 1, // [1:1] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name 1, // [1:1] is the sub-list for extension extendee 0, // [0:1] is the sub-list for field type_name } func init() { file_demo3_proto_init() } func file_demo3_proto_init() { if File_demo3_proto != nil { return } if !protoimpl.UnsafeEnabled { file_demo3_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Teacher); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_demo3_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Teacher_PhoneNumber); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_demo3_proto_rawDesc, NumEnums: 0, NumMessages: 2, NumExtensions: 0, NumServices: 0, }, GoTypes: file_demo3_proto_goTypes, DependencyIndexes: file_demo3_proto_depIdxs, MessageInfos: file_demo3_proto_msgTypes, }.Build() File_demo3_proto = out.File file_demo3_proto_rawDesc = nil file_demo3_proto_goTypes = nil file_demo3_proto_depIdxs = nil }
3>.enum關鍵字
//protobuf默認支持的版本是2.x,現在一般使用3.x版本,所以需要手動指定版本號,如果不這樣做,協議緩沖區編譯器將假定正在使用proto2。這也必須是文件的第一個非空的非注釋行。 syntax = "proto3"; //.proto文件應包含一個go_package選項,用於指定包含所生成代碼的Go軟件包的完整導入路徑(最后一次"bar"就是生成go文件的包名),官方在未來的發行版本會支持喲; option go_package ="example.com/foo/bar"; message Teacher{ //姓名 string name = 1; //年齡 int32 age = 2 ; //地址 string address = 3; //定義一個message message PhoneNumber{ string number = 1; PhoneType type = 2; } //repeadted關鍵字類似與go中的切片,編譯之后對應的也是go的切片 repeated PhoneNumber phone = 4 ; } //enum為關鍵字,作用為定義一種枚舉類型 enum PhoneType { /* enum還可以為不同的枚舉常量指定相同的值來定義別名。 如果想要使用這個功能必須講 allow_alias 選項設置為true,負責編譯器將報錯。 */ option allow_alias = true; /* 如下所示,enum的第一個常量映射為0,每個枚舉定義必須包含一個映射到零的常量作為其第一個元素。 這是因為必須有一個零值,以便我們可以使用0作為數字默認值。 零值必須是第一個元素,以便與proto2語義兼容,其中第一個枚舉值始終是默認值。 默認值 解析數據時,如果編碼的消息不包含特定的單數元素,則解析對象對象中的相應字段將設置為該字段的默認值。 不同類型的默認值不同,具體如下: 對於字符串,默認值為空字符串。 對於字節,默認值為空字節。 對於bools,默認值為false。 對於數字類型,默認值為零。 對於枚舉,默認值是第一個定義的枚舉值,該值必須為0。 repeated字段默認值是空列表 message字段的默認值為空對象 */ MOBILE = 0; HOME = 1; WORK = 2; Personal = 2; }

//protobuf默認支持的版本是2.x,現在一般使用3.x版本,所以需要手動指定版本號,如果不這樣做,協議緩沖區編譯器將假定正在使用proto2。這也必須是文件的第一個非空的非注釋行。 // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.21.0 // protoc v3.11.4 // source: demo4.proto package bar import ( proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) // This is a compile-time assertion that a sufficiently up-to-date version // of the legacy proto package is being used. const _ = proto.ProtoPackageIsVersion4 //enum為關鍵字,作用為定義一種枚舉類型 type PhoneType int32 const ( // //如下所示,enum的第一個常量映射為0,每個枚舉定義必須包含一個映射到零的常量作為其第一個元素。 //這是因為必須有一個零值,以便我們可以使用0作為數字默認值。 //零值必須是第一個元素,以便與proto2語義兼容,其中第一個枚舉值始終是默認值。 // //默認值 //解析數據時,如果編碼的消息不包含特定的單數元素,則解析對象對象中的相應字段將設置為該字段的默認值。 //不同類型的默認值不同,具體如下: //對於字符串,默認值為空字符串。 //對於字節,默認值為空字節。 //對於bools,默認值為false。 //對於數字類型,默認值為零。 //對於枚舉,默認值是第一個定義的枚舉值,該值必須為0。 //repeated字段默認值是空列表 //message字段的默認值為空對象 PhoneType_MOBILE PhoneType = 0 PhoneType_HOME PhoneType = 1 PhoneType_WORK PhoneType = 2 PhoneType_Personal PhoneType = 2 ) // Enum value maps for PhoneType. var ( PhoneType_name = map[int32]string{ 0: "MOBILE", 1: "HOME", 2: "WORK", // Duplicate value: 2: "Personal", } PhoneType_value = map[string]int32{ "MOBILE": 0, "HOME": 1, "WORK": 2, "Personal": 2, } ) func (x PhoneType) Enum() *PhoneType { p := new(PhoneType) *p = x return p } func (x PhoneType) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } func (PhoneType) Descriptor() protoreflect.EnumDescriptor { return file_demo4_proto_enumTypes[0].Descriptor() } func (PhoneType) Type() protoreflect.EnumType { return &file_demo4_proto_enumTypes[0] } func (x PhoneType) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } // Deprecated: Use PhoneType.Descriptor instead. func (PhoneType) EnumDescriptor() ([]byte, []int) { return file_demo4_proto_rawDescGZIP(), []int{0} } type Teacher struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields //姓名 Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` //年齡 Age int32 `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"` //地址 Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` //repeadted關鍵字類似與go中的切片,編譯之后對應的也是go的切片 Phone []*Teacher_PhoneNumber `protobuf:"bytes,4,rep,name=phone,proto3" json:"phone,omitempty"` } func (x *Teacher) Reset() { *x = Teacher{} if protoimpl.UnsafeEnabled { mi := &file_demo4_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Teacher) String() string { return protoimpl.X.MessageStringOf(x) } func (*Teacher) ProtoMessage() {} func (x *Teacher) ProtoReflect() protoreflect.Message { mi := &file_demo4_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Teacher.ProtoReflect.Descriptor instead. func (*Teacher) Descriptor() ([]byte, []int) { return file_demo4_proto_rawDescGZIP(), []int{0} } func (x *Teacher) GetName() string { if x != nil { return x.Name } return "" } func (x *Teacher) GetAge() int32 { if x != nil { return x.Age } return 0 } func (x *Teacher) GetAddress() string { if x != nil { return x.Address } return "" } func (x *Teacher) GetPhone() []*Teacher_PhoneNumber { if x != nil { return x.Phone } return nil } //定義一個message type Teacher_PhoneNumber struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Number string `protobuf:"bytes,1,opt,name=number,proto3" json:"number,omitempty"` Type PhoneType `protobuf:"varint,2,opt,name=type,proto3,enum=PhoneType" json:"type,omitempty"` } func (x *Teacher_PhoneNumber) Reset() { *x = Teacher_PhoneNumber{} if protoimpl.UnsafeEnabled { mi := &file_demo4_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Teacher_PhoneNumber) String() string { return protoimpl.X.MessageStringOf(x) } func (*Teacher_PhoneNumber) ProtoMessage() {} func (x *Teacher_PhoneNumber) ProtoReflect() protoreflect.Message { mi := &file_demo4_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Teacher_PhoneNumber.ProtoReflect.Descriptor instead. func (*Teacher_PhoneNumber) Descriptor() ([]byte, []int) { return file_demo4_proto_rawDescGZIP(), []int{0, 0} } func (x *Teacher_PhoneNumber) GetNumber() string { if x != nil { return x.Number } return "" } func (x *Teacher_PhoneNumber) GetType() PhoneType { if x != nil { return x.Type } return PhoneType_MOBILE } var File_demo4_proto protoreflect.FileDescriptor var file_demo4_proto_rawDesc = []byte{ 0x0a, 0x0b, 0x64, 0x65, 0x6d, 0x6f, 0x34, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xbc, 0x01, 0x0a, 0x07, 0x54, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x54, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x1a, 0x45, 0x0a, 0x0b, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x2a, 0x3d, 0x0a, 0x09, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x4f, 0x42, 0x49, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x4f, 0x4d, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x4f, 0x52, 0x4b, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x10, 0x02, 0x1a, 0x02, 0x10, 0x01, 0x42, 0x15, 0x5a, 0x13, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6f, 0x6f, 0x2f, 0x62, 0x61, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_demo4_proto_rawDescOnce sync.Once file_demo4_proto_rawDescData = file_demo4_proto_rawDesc ) func file_demo4_proto_rawDescGZIP() []byte { file_demo4_proto_rawDescOnce.Do(func() { file_demo4_proto_rawDescData = protoimpl.X.CompressGZIP(file_demo4_proto_rawDescData) }) return file_demo4_proto_rawDescData } var file_demo4_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_demo4_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_demo4_proto_goTypes = []interface{}{ (PhoneType)(0), // 0: PhoneType (*Teacher)(nil), // 1: Teacher (*Teacher_PhoneNumber)(nil), // 2: Teacher.PhoneNumber } var file_demo4_proto_depIdxs = []int32{ 2, // 0: Teacher.phone:type_name -> Teacher.PhoneNumber 0, // 1: Teacher.PhoneNumber.type:type_name -> PhoneType 2, // [2:2] is the sub-list for method output_type 2, // [2:2] is the sub-list for method input_type 2, // [2:2] is the sub-list for extension type_name 2, // [2:2] is the sub-list for extension extendee 0, // [0:2] is the sub-list for field type_name } func init() { file_demo4_proto_init() } func file_demo4_proto_init() { if File_demo4_proto != nil { return } if !protoimpl.UnsafeEnabled { file_demo4_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Teacher); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_demo4_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Teacher_PhoneNumber); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_demo4_proto_rawDesc, NumEnums: 1, NumMessages: 2, NumExtensions: 0, NumServices: 0, }, GoTypes: file_demo4_proto_goTypes, DependencyIndexes: file_demo4_proto_depIdxs, EnumInfos: file_demo4_proto_enumTypes, MessageInfos: file_demo4_proto_msgTypes, }.Build() File_demo4_proto = out.File file_demo4_proto_rawDesc = nil file_demo4_proto_goTypes = nil file_demo4_proto_depIdxs = nil }
4>.oneof關鍵字(C語言中的聯合體)
//protobuf默認支持的版本是2.x,現在一般使用3.x版本,所以需要手動指定版本號,如果不這樣做,協議緩沖區編譯器將假定正在使用proto2。這也必須是文件的第一個非空的非注釋行。 syntax = "proto3"; //.proto文件應包含一個go_package選項,用於指定包含所生成代碼的Go軟件包的完整導入路徑(最后一次"bar"就是生成go文件的包名),官方在未來的發行版本會支持喲; option go_package ="example.com/foo/bar"; message Teacher{ //姓名 string name = 1; //年齡 int32 age = 2 ; //地址 string address = 3; //定義一個message message PhoneNumber{ string number = 1; PhoneType type = 2; } //repeadted關鍵字類似與go中的切片,編譯之后對應的也是go的切片 repeated PhoneNumber phone = 4 ; //如果有一個包含許多字段的消息,並且多只能同時設置其中的一個字段,則可以使用oneof功能 oneof data{ string school = 5; int32 score = 6; } } //enum為關鍵字,作用為定義一種枚舉類型 enum PhoneType { /* enum還可以為不同的枚舉常量指定相同的值來定義別名。 如果想要使用這個功能必須講 allow_alias 選項設置為true,負責編譯器將報錯。 */ option allow_alias = true; /* 如下所示,enum的第一個常量映射為0,每個枚舉定義必須包含一個映射到零的常量作為其第一個元素。 這是因為必須有一個零值,以便我們可以使用0作為數字默認值。 零值必須是第一個元素,以便與proto2語義兼容,其中第一個枚舉值始終是默認值。 默認值 解析數據時,如果編碼的消息不包含特定的單數元素,則解析對象對象中的相應字段將設置為該字段的默認值。 不同類型的默認值不同,具體如下: 對於字符串,默認值為空字符串。 對於字節,默認值為空字節。 對於bools,默認值為false。 對於數字類型,默認值為零。 對於枚舉,默認值是第一個定義的枚舉值,該值必須為0。 repeated字段默認值是空列表 message字段的默認值為空對象 */ MOBILE = 0; HOME = 1; WORK = 2; Personal = 2; }

//protobuf默認支持的版本是2.x,現在一般使用3.x版本,所以需要手動指定版本號,如果不這樣做,協議緩沖區編譯器將假定正在使用proto2。這也必須是文件的第一個非空的非注釋行。 // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.21.0 // protoc v3.11.4 // source: demo5.proto package bar import ( proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) // This is a compile-time assertion that a sufficiently up-to-date version // of the legacy proto package is being used. const _ = proto.ProtoPackageIsVersion4 //enum為關鍵字,作用為定義一種枚舉類型 type PhoneType int32 const ( // //如下所示,enum的第一個常量映射為0,每個枚舉定義必須包含一個映射到零的常量作為其第一個元素。 //這是因為必須有一個零值,以便我們可以使用0作為數字默認值。 //零值必須是第一個元素,以便與proto2語義兼容,其中第一個枚舉值始終是默認值。 // //默認值 //解析數據時,如果編碼的消息不包含特定的單數元素,則解析對象對象中的相應字段將設置為該字段的默認值。 //不同類型的默認值不同,具體如下: //對於字符串,默認值為空字符串。 //對於字節,默認值為空字節。 //對於bools,默認值為false。 //對於數字類型,默認值為零。 //對於枚舉,默認值是第一個定義的枚舉值,該值必須為0。 //repeated字段默認值是空列表 //message字段的默認值為空對象 PhoneType_MOBILE PhoneType = 0 PhoneType_HOME PhoneType = 1 PhoneType_WORK PhoneType = 2 PhoneType_Personal PhoneType = 2 ) // Enum value maps for PhoneType. var ( PhoneType_name = map[int32]string{ 0: "MOBILE", 1: "HOME", 2: "WORK", // Duplicate value: 2: "Personal", } PhoneType_value = map[string]int32{ "MOBILE": 0, "HOME": 1, "WORK": 2, "Personal": 2, } ) func (x PhoneType) Enum() *PhoneType { p := new(PhoneType) *p = x return p } func (x PhoneType) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } func (PhoneType) Descriptor() protoreflect.EnumDescriptor { return file_demo5_proto_enumTypes[0].Descriptor() } func (PhoneType) Type() protoreflect.EnumType { return &file_demo5_proto_enumTypes[0] } func (x PhoneType) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } // Deprecated: Use PhoneType.Descriptor instead. func (PhoneType) EnumDescriptor() ([]byte, []int) { return file_demo5_proto_rawDescGZIP(), []int{0} } type Teacher struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields //姓名 Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` //年齡 Age int32 `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"` //地址 Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` //repeadted關鍵字類似與go中的切片,編譯之后對應的也是go的切片 Phone []*Teacher_PhoneNumber `protobuf:"bytes,4,rep,name=phone,proto3" json:"phone,omitempty"` //如果有一個包含許多字段的消息,並且多只能同時設置其中的一個字段,則可以使用oneof功能 // // Types that are assignable to Data: // *Teacher_School // *Teacher_Score Data isTeacher_Data `protobuf_oneof:"data"` } func (x *Teacher) Reset() { *x = Teacher{} if protoimpl.UnsafeEnabled { mi := &file_demo5_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Teacher) String() string { return protoimpl.X.MessageStringOf(x) } func (*Teacher) ProtoMessage() {} func (x *Teacher) ProtoReflect() protoreflect.Message { mi := &file_demo5_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Teacher.ProtoReflect.Descriptor instead. func (*Teacher) Descriptor() ([]byte, []int) { return file_demo5_proto_rawDescGZIP(), []int{0} } func (x *Teacher) GetName() string { if x != nil { return x.Name } return "" } func (x *Teacher) GetAge() int32 { if x != nil { return x.Age } return 0 } func (x *Teacher) GetAddress() string { if x != nil { return x.Address } return "" } func (x *Teacher) GetPhone() []*Teacher_PhoneNumber { if x != nil { return x.Phone } return nil } func (m *Teacher) GetData() isTeacher_Data { if m != nil { return m.Data } return nil } func (x *Teacher) GetSchool() string { if x, ok := x.GetData().(*Teacher_School); ok { return x.School } return "" } func (x *Teacher) GetScore() int32 { if x, ok := x.GetData().(*Teacher_Score); ok { return x.Score } return 0 } type isTeacher_Data interface { isTeacher_Data() } type Teacher_School struct { School string `protobuf:"bytes,5,opt,name=school,proto3,oneof"` } type Teacher_Score struct { Score int32 `protobuf:"varint,6,opt,name=score,proto3,oneof"` } func (*Teacher_School) isTeacher_Data() {} func (*Teacher_Score) isTeacher_Data() {} //定義一個message type Teacher_PhoneNumber struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Number string `protobuf:"bytes,1,opt,name=number,proto3" json:"number,omitempty"` Type PhoneType `protobuf:"varint,2,opt,name=type,proto3,enum=PhoneType" json:"type,omitempty"` } func (x *Teacher_PhoneNumber) Reset() { *x = Teacher_PhoneNumber{} if protoimpl.UnsafeEnabled { mi := &file_demo5_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Teacher_PhoneNumber) String() string { return protoimpl.X.MessageStringOf(x) } func (*Teacher_PhoneNumber) ProtoMessage() {} func (x *Teacher_PhoneNumber) ProtoReflect() protoreflect.Message { mi := &file_demo5_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Teacher_PhoneNumber.ProtoReflect.Descriptor instead. func (*Teacher_PhoneNumber) Descriptor() ([]byte, []int) { return file_demo5_proto_rawDescGZIP(), []int{0, 0} } func (x *Teacher_PhoneNumber) GetNumber() string { if x != nil { return x.Number } return "" } func (x *Teacher_PhoneNumber) GetType() PhoneType { if x != nil { return x.Type } return PhoneType_MOBILE } var File_demo5_proto protoreflect.FileDescriptor var file_demo5_proto_rawDesc = []byte{ 0x0a, 0x0b, 0x64, 0x65, 0x6d, 0x6f, 0x35, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf6, 0x01, 0x0a, 0x07, 0x54, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x54, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x18, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x6f, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x73, 0x63, 0x68, 0x6f, 0x6f, 0x6c, 0x12, 0x16, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x1a, 0x45, 0x0a, 0x0b, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x2a, 0x3d, 0x0a, 0x09, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x4f, 0x42, 0x49, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x4f, 0x4d, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x4f, 0x52, 0x4b, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x10, 0x02, 0x1a, 0x02, 0x10, 0x01, 0x42, 0x15, 0x5a, 0x13, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6f, 0x6f, 0x2f, 0x62, 0x61, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_demo5_proto_rawDescOnce sync.Once file_demo5_proto_rawDescData = file_demo5_proto_rawDesc ) func file_demo5_proto_rawDescGZIP() []byte { file_demo5_proto_rawDescOnce.Do(func() { file_demo5_proto_rawDescData = protoimpl.X.CompressGZIP(file_demo5_proto_rawDescData) }) return file_demo5_proto_rawDescData } var file_demo5_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_demo5_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_demo5_proto_goTypes = []interface{}{ (PhoneType)(0), // 0: PhoneType (*Teacher)(nil), // 1: Teacher (*Teacher_PhoneNumber)(nil), // 2: Teacher.PhoneNumber } var file_demo5_proto_depIdxs = []int32{ 2, // 0: Teacher.phone:type_name -> Teacher.PhoneNumber 0, // 1: Teacher.PhoneNumber.type:type_name -> PhoneType 2, // [2:2] is the sub-list for method output_type 2, // [2:2] is the sub-list for method input_type 2, // [2:2] is the sub-list for extension type_name 2, // [2:2] is the sub-list for extension extendee 0, // [0:2] is the sub-list for field type_name } func init() { file_demo5_proto_init() } func file_demo5_proto_init() { if File_demo5_proto != nil { return } if !protoimpl.UnsafeEnabled { file_demo5_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Teacher); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_demo5_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Teacher_PhoneNumber); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } file_demo5_proto_msgTypes[0].OneofWrappers = []interface{}{ (*Teacher_School)(nil), (*Teacher_Score)(nil), } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_demo5_proto_rawDesc, NumEnums: 1, NumMessages: 2, NumExtensions: 0, NumServices: 0, }, GoTypes: file_demo5_proto_goTypes, DependencyIndexes: file_demo5_proto_depIdxs, EnumInfos: file_demo5_proto_enumTypes, MessageInfos: file_demo5_proto_msgTypes, }.Build() File_demo5_proto = out.File file_demo5_proto_rawDesc = nil file_demo5_proto_goTypes = nil file_demo5_proto_depIdxs = nil }
5>.定義RPC服務
//protobuf默認支持的版本是2.x,現在一般使用3.x版本,所以需要手動指定版本號,如果不這樣做,協議緩沖區編譯器將假定正在使用proto2。這也必須是文件的第一個非空的非注釋行。 syntax = "proto3"; //.proto文件應包含一個go_package選項,用於指定包含所生成代碼的Go軟件包的完整導入路徑(最后一次"bar"就是生成go文件的包名),官方在未來的發行版本會支持喲; option go_package ="example.com/foo/bar"; message Teacher{ //姓名 string name = 1; //年齡 int32 age = 2 ; //地址 string address = 3; } /* 如果需要將message與RPC一起使用,則可以在 .proto 文件中定義RPC服務接口,protobuf編譯器將根據你選擇的語言生成RPC接口代碼。 通過定義服務,然后借助框架幫助實現部分的rpc代碼 */ service HelloService { //傳入和傳輸的Teacher是咱們上面定義的message對象 rpc World (Teacher)returns (Teacher); }

//protobuf默認支持的版本是2.x,現在一般使用3.x版本,所以需要手動指定版本號,如果不這樣做,協議緩沖區編譯器將假定正在使用proto2。這也必須是文件的第一個非空的非注釋行。 // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.21.0 // protoc v3.11.4 // source: demo6.proto package bar import ( context "context" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) // This is a compile-time assertion that a sufficiently up-to-date version // of the legacy proto package is being used. const _ = proto.ProtoPackageIsVersion4 type Teacher struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields //姓名 Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` //年齡 Age int32 `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"` //地址 Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` } func (x *Teacher) Reset() { *x = Teacher{} if protoimpl.UnsafeEnabled { mi := &file_demo6_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Teacher) String() string { return protoimpl.X.MessageStringOf(x) } func (*Teacher) ProtoMessage() {} func (x *Teacher) ProtoReflect() protoreflect.Message { mi := &file_demo6_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Teacher.ProtoReflect.Descriptor instead. func (*Teacher) Descriptor() ([]byte, []int) { return file_demo6_proto_rawDescGZIP(), []int{0} } func (x *Teacher) GetName() string { if x != nil { return x.Name } return "" } func (x *Teacher) GetAge() int32 { if x != nil { return x.Age } return 0 } func (x *Teacher) GetAddress() string { if x != nil { return x.Address } return "" } var File_demo6_proto protoreflect.FileDescriptor var file_demo6_proto_rawDesc = []byte{ 0x0a, 0x0b, 0x64, 0x65, 0x6d, 0x6f, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x49, 0x0a, 0x07, 0x54, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x32, 0x2b, 0x0a, 0x0c, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x05, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x12, 0x08, 0x2e, 0x54, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x1a, 0x08, 0x2e, 0x54, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x42, 0x15, 0x5a, 0x13, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6f, 0x6f, 0x2f, 0x62, 0x61, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_demo6_proto_rawDescOnce sync.Once file_demo6_proto_rawDescData = file_demo6_proto_rawDesc ) func file_demo6_proto_rawDescGZIP() []byte { file_demo6_proto_rawDescOnce.Do(func() { file_demo6_proto_rawDescData = protoimpl.X.CompressGZIP(file_demo6_proto_rawDescData) }) return file_demo6_proto_rawDescData } var file_demo6_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_demo6_proto_goTypes = []interface{}{ (*Teacher)(nil), // 0: Teacher } var file_demo6_proto_depIdxs = []int32{ 0, // 0: HelloService.World:input_type -> Teacher 0, // 1: HelloService.World:output_type -> Teacher 1, // [1:2] is the sub-list for method output_type 0, // [0:1] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_demo6_proto_init() } func file_demo6_proto_init() { if File_demo6_proto != nil { return } if !protoimpl.UnsafeEnabled { file_demo6_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Teacher); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_demo6_proto_rawDesc, NumEnums: 0, NumMessages: 1, NumExtensions: 0, NumServices: 1, }, GoTypes: file_demo6_proto_goTypes, DependencyIndexes: file_demo6_proto_depIdxs, MessageInfos: file_demo6_proto_msgTypes, }.Build() File_demo6_proto = out.File file_demo6_proto_rawDesc = nil file_demo6_proto_goTypes = nil file_demo6_proto_depIdxs = nil } // Reference imports to suppress errors if they are not otherwise used. var _ context.Context var _ grpc.ClientConnInterface // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion6 // HelloServiceClient is the client API for HelloService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type HelloServiceClient interface { World(ctx context.Context, in *Teacher, opts ...grpc.CallOption) (*Teacher, error) } type helloServiceClient struct { cc grpc.ClientConnInterface } func NewHelloServiceClient(cc grpc.ClientConnInterface) HelloServiceClient { return &helloServiceClient{cc} } func (c *helloServiceClient) World(ctx context.Context, in *Teacher, opts ...grpc.CallOption) (*Teacher, error) { out := new(Teacher) err := c.cc.Invoke(ctx, "/HelloService/World", in, out, opts...) if err != nil { return nil, err } return out, nil } // HelloServiceServer is the server API for HelloService service. type HelloServiceServer interface { World(context.Context, *Teacher) (*Teacher, error) } // UnimplementedHelloServiceServer can be embedded to have forward compatible implementations. type UnimplementedHelloServiceServer struct { } func (*UnimplementedHelloServiceServer) World(context.Context, *Teacher) (*Teacher, error) { return nil, status.Errorf(codes.Unimplemented, "method World not implemented") } func RegisterHelloServiceServer(s *grpc.Server, srv HelloServiceServer) { s.RegisterService(&_HelloService_serviceDesc, srv) } func _HelloService_World_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Teacher) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(HelloServiceServer).World(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: "/HelloService/World", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(HelloServiceServer).World(ctx, req.(*Teacher)) } return interceptor(ctx, in, info, handler) } var _HelloService_serviceDesc = grpc.ServiceDesc{ ServiceName: "HelloService", HandlerType: (*HelloServiceServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "World", Handler: _HelloService_World_Handler, }, }, Streams: []grpc.StreamDesc{}, Metadata: "demo6.proto", }
五.報錯問題記錄
1>.Could not make proto path relative: protobuffer案例.proto: No such file or directory
報錯提示:
如下圖所示,明明文件是存在的,但是在生成golang代碼的時候總是提示找不到文件。
解決方案:
是由於文件名稱是中文導致的,將該文件名中文部分去掉就能解決該問題。
2>.--go_out: protoc-gen-go: Plugin failed with status code 1
錯誤提示: 如上圖所示,提示"protoc-gen-go"不是內部命令,因此我們需要安裝該工具。 解決方案: 查看"%GOPATH%\bin"目錄是否有protoc-gen-go命令。如果沒有就直接執行以下命令: go get -u github.com/golang/protobuf/protoc-gen-go
執行上述命令后會在"%GOPATH%\bin"目錄下生成一個protoc-gen-go的命令。如下圖所示。
3>.https fetch: Get https://google.golang.org/protobuf/types/descriptorpb?go-get=1: dial tcp 216.239.37.1:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
錯誤提示: 如上圖所示,提示遠程連接失敗,因為它訪問的是谷歌Google公司的公網地址,由於國內政策原因,我們無法直接訪問國外的一些特定的網站。 解決方案: 有以下兩種解決方案: (1)自行FQ; (2)配置代理; 博主推薦使用第二種解決方案,設置完下面幾個環境變量后,您的go命令將從公共代理鏡像中快速拉取您所需的依賴代碼了。如下圖所示,設置代理后咱們就可以下載所需要的工具啦~ go env -w GO111MODULE=on go env -w GOPROXY=https://goproxy.io,direct # 設置不走 proxy 的私有倉庫,多個用逗號相隔(可選) go env -w GOPRIVATE=*.corp.example.com 博主推薦閱讀: https://goproxy.io/zh/ https://goproxy.io/zh/docs/goproxyio-private.html