• Golang的序列化-ProtoBuf篇


                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%in目录生成一个编译工具"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
    }
    demo.pb.go

    四.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
    }
    使用命令"protoc --go_out=. demo2.proto"生成对应的Golang代码

    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
    }
    使用命令"protoc --go_out=. demo3.proto"生成对应的Golang代码

    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
    }
    使用命令"protoc --go_out=. demo4.proto"生成对应的Golang代码

    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
    }
    使用命令"protoc --go_out=. demo5.proto"生成对应的Golang代码

    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",
    }
    使用命令"protoc --go_out=plugins=grpc:. demo6.proto"生成对应的Golang代码

    五.报错问题记录

    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%in"目录是否有protoc-gen-go命令。如果没有就直接执行以下命令:    
          go get -u github.com/golang/protobuf/protoc-gen-go
        执行上述命令后会在"%GOPATH%in"目录下生成一个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)自行翻墙;
          (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

  • 相关阅读:
    mysql中表名是order的CRUD的错误
    BAT-增加JAVA环境变量(WIN764位)
    D7 D2007 XE10.1 都支持的字符分隔函数
    问题-百度云同步盘登陆时提示155010错误
    BAT-批量改文件后缀名
    delphi判断线程是否正在运行
    JAVA-JSP动作元素之param
    JAVA-JSP动作元素之forward
    JAVA-JSP动作元素之include
    JAVA-JSP之taglib指令
  • 原文地址:https://www.cnblogs.com/yinzhengjie2020/p/12741943.html
Copyright © 2020-2023  润新知