go/golang 新版 Protobuf API嚐鮮

簡介

Protobuf從v2用到了v3,從C++用到了Golang,個人特別喜歡。3月2日,Go官宣,有了新版的API。中文介紹 說實話,沒有太看明白。的確有點尷尬,從14年用到了20年,不過想那麼多幹嘛。用就完了。

因爲V2 API所涉及的新功能,目前我均未使用到,本文並未介紹

開始嘗試

先來個小demo

相關proto文件就不展示了
請注意引用新版API,不是github,而是google.golang.org
強烈建議大家開始使用go module,極度舒適,媽媽再也不擔心我拉不到代碼了!!!

package serverproto

import (
	"google.golang.org/protobuf/proto"
	"testing"
)

func TestBGFHead_GetUserId(t *testing.T) {
	head := &BGFHead{}
	head.UserId = 30020

	proto.Marshal(head)
}

go test走起,然而竟然報錯啦

[luojie@localhost serverproto]$ go test
# go/protobuf/serverproto [go/protobuf/serverproto.test]
./server_test.go:12:15: cannot use head (type *BGFHead) as type protoreflect.ProtoMessage in argument to "google.golang.org/protobuf/proto".Marshal:
	*BGFHead does not implement protoreflect.ProtoMessage (missing ProtoReflect method)
FAIL	go/protobuf/serverproto [build failed]

解決問題

因爲是新版V2 API並不向前兼容V1的API,所以此處需要更新protoc-gen-go 說明文檔

go install google.golang.org/protobuf/cmd/protoc-gen-go

使用了go module之後,install的速度也是快到飛起
!!!重新生成代碼 再次go test

[luojie@localhost serverproto]$ go test
PASS
ok  	go/protobuf/serverproto	0.003s

分析

V1的go代碼

type BGFHead struct {
	UserId               int32       `protobuf:"varint,1,opt,name=userId,proto3" json:"userId,omitempty"`
	Cmd                  uint32      `protobuf:"varint,2,opt,name=cmd,proto3" json:"cmd,omitempty"`
	TransTypes           TransType   `protobuf:"varint,3,opt,name=transTypes,proto3,enum=serverproto.TransType" json:"transTypes,omitempty"`
	MsgType              uint32      `protobuf:"varint,4,opt,name=msgType,proto3" json:"msgType,omitempty"`
	SSerId               int32       `protobuf:"varint,5,opt,name=sSerId,proto3" json:"sSerId,omitempty"`
	SSerType             ServerType  `protobuf:"varint,6,opt,name=sSerType,proto3,enum=serverproto.ServerType" json:"sSerType,omitempty"`
	DSerId               int32       `protobuf:"varint,7,opt,name=dSerId,proto3" json:"dSerId,omitempty"`
	DSerType             ServerType  `protobuf:"varint,8,opt,name=dSerType,proto3,enum=serverproto.ServerType" json:"dSerType,omitempty"`
	Cooks                []*CookInfo `protobuf:"bytes,9,rep,name=Cooks,proto3" json:"Cooks,omitempty"`
	GroupId              []int64     `protobuf:"varint,10,rep,packed,name=groupId,proto3" json:"groupId,omitempty"`
	XXX_NoUnkeyedLiteral struct{}    `json:"-"`
	XXX_unrecognized     []byte      `json:"-"`
	XXX_sizecache        int32       `json:"-"`
}
}

V2的go代碼

type BGFHead struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	UserId     int32       `protobuf:"varint,1,opt,name=userId,proto3" json:"userId,omitempty"`                                    //用戶id
	Cmd        uint32      `protobuf:"varint,2,opt,name=cmd,proto3" json:"cmd,omitempty"`                                          //命令字
	TransTypes TransType   `protobuf:"varint,3,opt,name=transTypes,proto3,enum=serverproto.TransType" json:"transTypes,omitempty"` //發送類型
	MsgType    uint32      `protobuf:"varint,4,opt,name=msgType,proto3" json:"msgType,omitempty"`                                  //消息類型
	SSerId     int32       `protobuf:"varint,5,opt,name=sSerId,proto3" json:"sSerId,omitempty"`                                    //源服務 id
	SSerType   ServerType  `protobuf:"varint,6,opt,name=sSerType,proto3,enum=serverproto.ServerType" json:"sSerType,omitempty"`    //源服務 type
	DSerId     int32       `protobuf:"varint,7,opt,name=dSerId,proto3" json:"dSerId,omitempty"`                                    //目標服務 id
	DSerType   ServerType  `protobuf:"varint,8,opt,name=dSerType,proto3,enum=serverproto.ServerType" json:"dSerType,omitempty"`    //目標服務 type
	Cooks      []*CookInfo `protobuf:"bytes,9,rep,name=Cooks,proto3" json:"Cooks,omitempty"`                                       //我也不知道是幹啥的
	GroupId    []int64     `protobuf:"varint,10,rep,packed,name=groupId,proto3" json:"groupId,omitempty"`                          //組id 與trans_types有關聯
}

結論

  • V2生成的go代碼含有proto文件中的註釋,個人非常喜歡,V1版本go代碼不包含註釋,複雜或者嵌套層次比較高的時候,沒有註釋,真是另人抓狂;
  • 在官宣說明中有提到舊版無意義的字段也沒有了;
  • V2代碼中新增了statesizeCacheunknownFields三個字段,具體意義有待研究;
  • V2中多引入兩個包,分別爲protoreflectprotoimpl

應用

若現有項目還在用V1的API,新項目想使用V2的API的簡單的方法

步驟

  • 修改當前的protoc-gen-go爲protoc-gen-goV1;
  • 安裝V2版本的protoc-gen-go;
  • 將protoc-gen-go修改爲protoc-gen-goV2;
  • 將protoc-gen-goV1修改爲protoc-gen-go;

Windows下同理

使用

V1版本

和原來一樣,沒有任何改變

V2版本

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