目录
它的优势及特点这里不赘述了,网上一大堆相关说明。
数据类型的对应表
.proto Type | C++ Type | Java Type | Go Type | PHP Type |
---|---|---|---|---|
double | double | double | float64 | float |
float | float | float | float32 | float |
int32 | int32 | int | int32 | integer |
int64 | int64 | long | int64 | integer/string |
uint32 | uint32 | int | uint32 | integer |
uint64 | uint64 | long | uint64 | integer/string |
sint32 | int32 | int | int32 | integer |
sint64 | int64 | long | int64 | integer/string |
fixed32 | uint32 | int | uint32 | integer |
fixed64 | uint64 | long | uint64 | integer/string |
sfixed32 | int32 | int | int32 | integer |
sfixed64 | int64 | long | int64 | integer/string |
bool | bool | boolean | bool | boolean |
string | string | String | string | string |
bytes | string | ByteString | []byte | string |
实践的一个例子
新建一个项目,新建一个目录存放.proto文件,这里以学生实体为例,尽可能多的使用了多个类型,目录下新建student.proto文件如下:
// 如不涉及rpc,可直接protoc --go_out=. *.proto
// 指定版本,此处采用proto3语法
syntax = "proto3";
//包名,通过protoc生成时的go文件对应的package
package student;
// 性别,枚举。枚举类型第一个字段必须为0
enum Gender {
Male = 0; // 男
Female = 1; // 女
}
// 学生信息
message Student {
int32 id = 1; // 学号
string name = 2; // 姓名
Gender gender = 3; // 性别
map<string, Course> Score = 4; // 该学生选修的课程及其对应的课程具体信息
}
message Course{
float duration = 1; // 课程周期,单位默认小时
float score = 2; // 所修学分
bool isPass = 3; // 考核结果是否通过
}
cd进入该.proto文件所在的目录下,终端执行命令protoc --go_out=. student.proto 或
protoc --go_out=. *.proto
多个的话用后者即可。该目录下会生成对应的student.pb.go
(生成方式及环境搭建可移步https://blog.csdn.net/HYZX_9987/article/details/106462026)
看看生成的go文件:
// 如不涉及rpc,可直接protoc --go_out=. *.proto
// 指定版本,此处采用proto3语法
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.24.0
// protoc v3.12.1
// source: student.proto
//包名,通过protoc生成时的go文件对应的package
package student
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
// 性别,枚举。枚举类型第一个字段必须为0
type Gender int32
const (
Gender_Male Gender = 0 // 男
Gender_Female Gender = 1 // 女
)
// Enum value maps for Gender.
var (
Gender_name = map[int32]string{
0: "Male",
1: "Female",
}
Gender_value = map[string]int32{
"Male": 0,
"Female": 1,
}
)
func (x Gender) Enum() *Gender {
p := new(Gender)
*p = x
return p
}
func (x Gender) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Gender) Descriptor() protoreflect.EnumDescriptor {
return file_student_proto_enumTypes[0].Descriptor()
}
func (Gender) Type() protoreflect.EnumType {
return &file_student_proto_enumTypes[0]
}
func (x Gender) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Gender.Descriptor instead.
func (Gender) EnumDescriptor() ([]byte, []int) {
return file_student_proto_rawDescGZIP(), []int{0}
}
// 学生信息
type Student struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // 学号
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // 姓名
Gender Gender `protobuf:"varint,3,opt,name=gender,proto3,enum=student.Gender" json:"gender,omitempty"` // 性别
Score map[string]*Course `protobuf:"bytes,4,rep,name=Score,proto3" json:"Score,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // 该学生选修的课程及其对应的课程具体信息
}
func (x *Student) Reset() {
*x = Student{}
if protoimpl.UnsafeEnabled {
mi := &file_student_proto_msgTypes[0]
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_student_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 Student.ProtoReflect.Descriptor instead.
func (*Student) Descriptor() ([]byte, []int) {
return file_student_proto_rawDescGZIP(), []int{0}
}
func (x *Student) GetId() int32 {
if x != nil {
return x.Id
}
return 0
}
func (x *Student) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *Student) GetGender() Gender {
if x != nil {
return x.Gender
}
return Gender_Male
}
func (x *Student) GetScore() map[string]*Course {
if x != nil {
return x.Score
}
return nil
}
type Course struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Duration float32 `protobuf:"fixed32,1,opt,name=duration,proto3" json:"duration,omitempty"` // 课程周期,单位默认小时
Score float32 `protobuf:"fixed32,2,opt,name=score,proto3" json:"score,omitempty"` // 所修学分
IsPass bool `protobuf:"varint,3,opt,name=isPass,proto3" json:"isPass,omitempty"` // 考核结果是否通过
}
func (x *Course) Reset() {
*x = Course{}
if protoimpl.UnsafeEnabled {
mi := &file_student_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Course) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Course) ProtoMessage() {}
func (x *Course) ProtoReflect() protoreflect.Message {
mi := &file_student_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 Course.ProtoReflect.Descriptor instead.
func (*Course) Descriptor() ([]byte, []int) {
return file_student_proto_rawDescGZIP(), []int{1}
}
func (x *Course) GetDuration() float32 {
if x != nil {
return x.Duration
}
return 0
}
func (x *Course) GetScore() float32 {
if x != nil {
return x.Score
}
return 0
}
func (x *Course) GetIsPass() bool {
if x != nil {
return x.IsPass
}
return false
}
var File_student_proto protoreflect.FileDescriptor
var file_student_proto_rawDesc = []byte{
0x0a, 0x0d, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x07, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x22, 0xd4, 0x01, 0x0a, 0x07, 0x53, 0x74, 0x75,
0x64, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05,
0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x67, 0x65, 0x6e, 0x64,
0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x73, 0x74, 0x75, 0x64, 0x65,
0x6e, 0x74, 0x2e, 0x47, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x52, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65,
0x72, 0x12, 0x31, 0x0a, 0x05, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x1b, 0x2e, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x75, 0x64, 0x65,
0x6e, 0x74, 0x2e, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x53,
0x63, 0x6f, 0x72, 0x65, 0x1a, 0x49, 0x0a, 0x0a, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x45, 0x6e, 0x74,
0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x03, 0x6b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f,
0x75, 0x72, 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22,
0x52, 0x0a, 0x06, 0x43, 0x6f, 0x75, 0x72, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x75, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02, 0x52, 0x08, 0x64, 0x75, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x69,
0x73, 0x50, 0x61, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x50,
0x61, 0x73, 0x73, 0x2a, 0x1e, 0x0a, 0x06, 0x47, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x08, 0x0a,
0x04, 0x4d, 0x61, 0x6c, 0x65, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x65, 0x6d, 0x61, 0x6c,
0x65, 0x10, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_student_proto_rawDescOnce sync.Once
file_student_proto_rawDescData = file_student_proto_rawDesc
)
func file_student_proto_rawDescGZIP() []byte {
file_student_proto_rawDescOnce.Do(func() {
file_student_proto_rawDescData = protoimpl.X.CompressGZIP(file_student_proto_rawDescData)
})
return file_student_proto_rawDescData
}
var file_student_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_student_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_student_proto_goTypes = []interface{}{
(Gender)(0), // 0: student.Gender
(*Student)(nil), // 1: student.Student
(*Course)(nil), // 2: student.Course
nil, // 3: student.Student.ScoreEntry
}
var file_student_proto_depIdxs = []int32{
0, // 0: student.Student.gender:type_name -> student.Gender
3, // 1: student.Student.Score:type_name -> student.Student.ScoreEntry
2, // 2: student.Student.ScoreEntry.value:type_name -> student.Course
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_student_proto_init() }
func file_student_proto_init() {
if File_student_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_student_proto_msgTypes[0].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
}
}
file_student_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Course); 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_student_proto_rawDesc,
NumEnums: 1,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_student_proto_goTypes,
DependencyIndexes: file_student_proto_depIdxs,
EnumInfos: file_student_proto_enumTypes,
MessageInfos: file_student_proto_msgTypes,
}.Build()
File_student_proto = out.File
file_student_proto_rawDesc = nil
file_student_proto_goTypes = nil
file_student_proto_depIdxs = nil
}
新建main.go随便搞点数据,分别以json和protobuf进行byte和结构化之间的转换,如下:
package main
import (
"encoding/json"
"fmt"
"github.com/golang/protobuf/proto"
student "protobuf-basic/protobuf"
)
func makeStudent(id int32, name, courseName string, gender student.Gender, duration, score float32) *student.Student {
stu := &student.Student{
Id: id,
Name: name,
Gender: gender,
Score: map[string]*student.Course{
"哲学": &student.Course{
Duration: 16.0,
Score: 2.5,
IsPass: true,
},
courseName: &student.Course{
Duration: duration,
Score: score,
IsPass: true,
},
},
}
return stu
}
func main() {
stu0 := makeStudent(1416271200, "王五", "中外音乐鉴赏", student.Gender_Male, 14.5, 2.0)
b0, _ := json.Marshal(stu0) // 编码
fmt.Println("[json-byte]学生:", b0)
s0 := &student.Student{}
json.Unmarshal(b0, s0) // 解码
fmt.Println("[struct]学生:", s0)
fmt.Println("------------------------")
stu1 := makeStudent(1416271201, "王六", "中外音乐鉴赏", student.Gender_Male, 14.5, 2.0)
b1, _ := proto.Marshal(stu1) // 编码
fmt.Println("[protobuf-byte]学生:", b1)
s1 := &student.Student{}
proto.Unmarshal(b1, s1) // 解码
fmt.Print("[struct]学生:", s1)
}
控制台:
[json-byte]学生: [123 34 105 100 34 58 49 52 49 54 50 55 49 50 48 48 44 34 110 9
7 109 101 34 58 34 231 142 139 228 186 148 34 44 34 83 99 111 114 101 34 58 123
34 228 184 173 229 164 150 233 159 179 228 185 144 233 137 180 232 181 143 34 58
123 34 100 117 114 97 116 105 111 110 34 58 49 52 46 53 44 34 115 99 111 114 10
1 34 58 50 44 34 105 115 80 97 115 115 34 58 116 114 117 101 125 44 34 229 147 1
78 229 173 166 34 58 123 34 100 117 114 97 116 105 111 110 34 58 49 54 44 34 115
99 111 114 101 34 58 50 46 53 44 34 105 115 80 97 115 115 34 58 116 114 117 101
125 125 125]
[struct]学生: id:1416271200 name:"王五" Score:{key:"中外音乐鉴赏" value:{dura
tion:14.5 score:2 isPass:true}} Score:{key:"哲学" value:{duration:16 score:
2.5 isPass:true}}
------------------------
[protobuf-byte]学生: [8 225 170 170 163 5 18 6 231 142 139 229 133 173 34 22 10
6 229 147 178 229 173 166 18 12 13 0 0 128 65 21 0 0 32 64 24 1 34 34 10 18 228
184 173 229 164 150 233 159 179 228 185 144 233 137 180 232 181 143 18 12 13 0 0
104 65 21 0 0 0 64 24 1]
[struct]学生:id:1416271201 name:"王六" Score:{key:"中外音乐鉴赏" value:{durat
ion:14.5 score:2 isPass:true}} Score:{key:"哲学" value:{duration:16 score:2
.5 isPass:true}}