gopher:試試protobuf ?

目錄

數據類型的對應表

實踐的一個例子


它的優勢及特點這裏不贅述了,網上一大堆相關說明。

數據類型的對應表

.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}}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章