欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

gopher:试试protobuf ?

程序员文章站 2022-05-10 23:32:01
...

目录

数据类型的对应表

实践的一个例子


它的优势及特点这里不赘述了,网上一大堆相关说明。

数据类型的对应表

.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

gopher:试试protobuf ?

看看生成的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}}

 

 

 

相关标签: 传输/存储