原文:https://www.jianshu.com/p/744d8c080d59
----------------------------
protobuf導出golang,調整默認tag的方法
問題概述
在protobuf導出到golang的時候,生成的.go文件里的struct的tag是沒辦法靈活設置的,以下面這個message為例
test.proto
syntax=proto3;
package test;
option go_package = ".;test";
message MyMessage {
int64 Code = 1;
}
執行protoc --proto_path=. --go_out=. test.proto導出的test.pb.go里的MyMessage這個結構體的定義會是這樣:
type MyMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Code int64 `protobuf:"varint,1,opt,name=Code,proto3" json:"Code,omitempty"` }
可以看到Code字段的protobuf和json的tag都是固定的(目前還沒有找到方法能通過protoc命令的參數來設置tag),但是這樣的struct有時候並不是我們所期待的,比如下面的代碼片段:
msg := &MyMessage{Code: 0} bdata, _ := json.Marshal(msg) fmt.Println(string(bdata))
這段代碼最終的輸出會是{}
,因為Code的json tag設置了omitempty,這種情況在開發過程中有時候是很蛋疼的,因為即便Code是默認值0,我們也還是希望能打印出來的。因此我們需要一種方法能通過在編寫proto文件的時候,在里面注入tag,然后導出成go的時候這個被注入的字段的tag可以自定義。
解決方法
- protoc-go-inject-tag: https://github.com/favadi/protoc-go-inject-tag
- 安裝:go get https://github.com/favadi/protoc-go-inject-tag
- 這個庫可以在proto文件中注入tag,然后在導出的時候相應的字段的tag就可以被修改掉了。具體做法如下:
test.proto
syntax=proto3; package test; option go_package = ".;test"; message MyMessage { // @inject_tag: json:"Code" int64 Code = 1; }
可以看到與之前不同的是我們在Code這個字段上面加了一行注釋// @inject_tag: json:"Code"
。
執行
protoc --proto_path=. --go_out=. test.proto
protoprotoc-go-inject-tag -input=./test.pb.go
這時候導出的test.pb.go文件里的MyMessage結構體如下:
type MyMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // @inject_tag: json:"Code" Code int64 `protobuf:"varint,1,opt,name=Code,proto3" json:"Code"` }
可以看到Code字段的json tag里的omitempty沒有了,這時候如果我們再執行
msg := &MyMessage{Code: 0} bdata, _ := json.Marshal(msg) fmt.Println(string(bdata))
這個代碼片段,輸出就是{"Code": 0}
了。達到我們的目的了。當然inject_tag不僅僅可以設置json的tag,它可以設置任何的tag。
總結
protobuf的protoc工具導出golang的時候,導出的結構體的tag是固定死的,在實際的使用中會導致很多不方便或是不靈活,通過protoc-go-inject-tag這個工具,可以inject tag,這樣就能靈活的調整導出的pb.go文件里的結構體的tag。
作者:大菜狗RookieDog
鏈接:https://www.jianshu.com/p/744d8c080d59
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。