Go語(yǔ)言使用protojson庫(kù)實(shí)現(xiàn)Protocol Buffers與JSON轉(zhuǎn)換
Protojson 簡(jiǎn)介
Protojson是Google針對(duì)Protocol Buffers數(shù)據(jù)格式的JSON編碼庫(kù),為Go語(yǔ)言開(kāi)發(fā)人員提供了便捷的工具和API,用于Protocol Buffers消息與JSON之間的轉(zhuǎn)換。常用API:
func Format(m proto.Message) string func Marshal(m proto.Message) ([]byte, error) func Unmarshal(b []byte, m proto.Message) error type MarshalOptions func (o MarshalOptions) Format(m proto.Message) string func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) func (o MarshalOptions) MarshalAppend(b []byte, m proto.Message) ([]byte, error) type UnmarshalOptions func (o UnmarshalOptions) Unmarshal(b []byte, m proto.Message) error
接著,我們通過(guò)一些實(shí)踐例子來(lái)演示如何使用。
安裝protoc
- 設(shè)置Go Env(window os)
# go env -w GOPROXY=https://goproxy.cn # go env -w GOBIN=%USERPROFILE%\go\bin
其中 USERPROFILE 為默認(rèn)用戶安裝路徑,example: C:\Users\jeffff
- 下載安裝
下載適合自己os的protoc版本,復(fù)制到GOBIN目錄下,下載鏈接https://github.com/protocolbuffers/protobuf/releases
- 檢查是否安裝成功
# protoc --version libprotoc 24.3
安裝protoc-gen-go
這里采用 go install安裝,安裝成功后會(huì)添加到GOBIN目錄下
# go install google.golang.org/protobuf/cmd/protoc-gen-go@latest # protoc-gen-go --version protoc-gen-go v1.31.0
Example
創(chuàng)建/example/example.proto 創(chuàng)建/exmpale/main.go
syntax = "proto3"; package example.pb; option go_package = "./;pb"; message User { string id = 1; string name = 3; int32 age = 4; string real_name = 5; string date = 8; }
執(zhí)行如下命令,生成/example/example.pb.go文件
#protoc --go_out=. example.proto
創(chuàng)建main.go,快速實(shí)踐各個(gè)API的功能
package main import ( "fmt" "github.com/google/uuid" "github.com/luckytking/practices/libs/protojson/pb" "google.golang.org/protobuf/encoding/protojson" ) func userInfo() *pb.User { return &pb.User{ Id: uuid.NewString(), Name: uuid.NewString(), Age: 33, RealName: uuid.NewString(), Date: "", //Date: time.Now().Format(time.DateTime), } } func main() { info := userInfo() fmt.Println("data.Src:", info) format := protojson.Format(info) fmt.Println("data.Format:", format) marshal, err := protojson.Marshal(info) if err != nil { panic(err) } fmt.Println("data.Marshal:", string(marshal)) user1 := &pb.User{} err = protojson.Unmarshal(marshal, user1) fmt.Println("data.Unmarshal:", user1) //marshalOpt := marshal2, err := protojson.MarshalOptions{ EmitUnpopulated: true, }.Marshal(info) if err != nil { panic(err) } fmt.Println("data.Marshal2:", string(marshal2)) user2 := &pb.User{} err = protojson.Unmarshal(marshal2, user2) fmt.Println("data.Unmarshal2:", user2) }
輸出如下:
data.Src: id:"df8bbcca-d8b9-4e41-91ff-6ccf01567d27" name:"67115015-48bb-4284-b601-e9348a53d40f" age:33 real_name:"bed916f1-0fb3-413c-9de3-222cbc90c814" data.Format: { "id": "df8bbcca-d8b9-4e41-91ff-6ccf01567d27", "name": "67115015-48bb-4284-b601-e9348a53d40f", "age": 33, "realName": "bed916f1-0fb3-413c-9de3-222cbc90c814" } data.Marshal: {"id":"df8bbcca-d8b9-4e41-91ff-6ccf01567d27", "name":"67115015-48bb-4284-b601-e9348a53d40f", "age":33, "realName":"bed916f1-0fb3-413c-9de3-222cbc90c814"} data.Unmarshal: id:"df8bbcca-d8b9-4e41-91ff-6ccf01567d27" name:"67115015-48bb-4284-b601-e9348a53d40f" age:33 real_name:"bed916f1-0fb3-413c-9de3-222cbc90c814" data.Marshal2: {"id":"df8bbcca-d8b9-4e41-91ff-6ccf01567d27", "name":"67115015-48bb-4284-b601-e9348a53d40f", "age":33, "realName":"bed916f1-0fb3-413c-9de3-222cbc90c814", "date":""} data.Unmarshal2: id:"df8bbcca-d8b9-4e41-91ff-6ccf01567d27" name:"67115015-48bb-4284-b601-e9348a53d40f" age:33 real_name:"bed916f1-0fb3-413c-9de3-222cbc90c814"
上例中:
- 通過(guò) Marshal 或 MarshalOptions.Marshal 函數(shù)將 protobuf 轉(zhuǎn)換為 JSON 格式.
- 通過(guò) Unmarshal 或 MarshalOptions.Unmarshal 函數(shù)將JSON 格式的數(shù)據(jù)轉(zhuǎn)換為 protobuf 消息.
- MarshalOptions 提供了一些自定義選項(xiàng),例如例子中 "EmitUnpopulated: true," 是否輸出未設(shè)置的字段. 這里雖然user.Data=""(默認(rèn)值),但還是輸出了空字符。
更多的option參考
type MarshalOptions struct { pragma.NoUnkeyedLiterals // Multiline 指定封送拆收器是否應(yīng)以縮進(jìn)形式格式化輸出,并將每個(gè)文本元素放在新行上。// 如果 Indent 是空字符串,則選擇任意縮進(jìn)。 Multiline bool // Indent 指定在多行格式化輸出中使用的縮進(jìn)字符集, 以便每個(gè)條目前面都有縮進(jìn),并且 // 以換行符結(jié)尾。如果非空,則 Multiline 被視為 true。 // 縮進(jìn)只能由空格或制表符組成。 Indent string // AllowPartial 允許對(duì)缺少必填字段的消息進(jìn)行封送 // 而不返回錯(cuò)誤。如果AllowPartial 為 false(默認(rèn)值), // 如果缺少任何必填字段,Marshal 將返回錯(cuò)誤。 AllowPartial bool // UseProtoNames 在 JSON字段名稱中使用 proto 字段名稱而不是小駝峰命名。 UseProtoNames bool // UseEnumNumbers 將枚舉值作為數(shù)字發(fā)出。 UseEnumNumbers bool // EmitUnpopulated 指定是否發(fā)出未填充的字段。//它不會(huì) 發(fā)出未填充的 oneof 字段或未填充的擴(kuò)展字段。 // 未填充字段發(fā)出的 JSON 值如下: // ╔═══════╤════════════════════════════╗ // ║ JSON │ Protobuf field ║ // ╠═══════╪════════════════════════════╣ // ║ false │ proto3 boolean fields ║ // ║ 0 │ proto3 numeric fields ║ // ║ "" │ proto3 string/bytes fields ║ // ║ null │ proto2 scalar fields ║ // ║ null │ message fields ║ // ║ [] │ list fields ║ // ║ {} │ map fields ║ // ╚═══════╧════════════════════════════╝ EmitUnpopulated bool // 解析器用于在擴(kuò)展 google.protobuf.Any // 消息時(shí)查找類型。如果為零,則默認(rèn)使用 protoregistry.GlobalTypes。 Resolver interface { protoregistry.ExtensionTypeResolver protoregistry.MessageTypeResolver } }
性能對(duì)比 protojson VS encoding/json
創(chuàng)建example_test.go
package main import ( "encoding/json" "google.golang.org/protobuf/encoding/protojson" "testing" ) func BenchmarkProtoJson(b *testing.B) { gen := userInfo() for i := 0; i < b.N; i++ { protojson.Marshal(gen) } } func BenchmarkStdJson(b *testing.B) { gen := userInfo() for i := 0; i < b.N; i++ { json.Marshal(gen) } }
結(jié)論如下:
BenchmarkProtoJson BenchmarkProtoJson-4 230895 4556 ns/op BenchmarkStdJson BenchmarkStdJson-4 715443 1732 ns/op
總結(jié)
本文通過(guò)實(shí)踐例子介紹Protojson庫(kù)實(shí)現(xiàn)Protocol Buffers與JSON之間的轉(zhuǎn)換,以及其和標(biāo)準(zhǔn)庫(kù)encoding/json性能對(duì)比。總的來(lái)說(shuō),利用Google Protocol Buffers定制API協(xié)議,和采用Protojson解決傳輸格式轉(zhuǎn)換。在分布式系統(tǒng)無(wú)論是Rpc還是Http的網(wǎng)絡(luò)通信,相信Protojson可以發(fā)揮不錯(cuò)的表現(xiàn)。
以上就是Go語(yǔ)言使用protojson庫(kù)實(shí)現(xiàn)Protocol Buffers與JSON轉(zhuǎn)換的詳細(xì)內(nèi)容,更多關(guān)于Go Protocol Buffers與JSON轉(zhuǎn)換的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Go?函數(shù)中獲取調(diào)用者的函數(shù)名和文件名及行號(hào)
這篇文章主要介紹了Go?函數(shù)中獲取調(diào)用者的函數(shù)名和文件名及行號(hào),文章圍主題詳細(xì)內(nèi)容展開(kāi)相關(guān)介紹,感興趣的小伙伴可以參考一下2022-05-05Golang?WorkerPool線程池并發(fā)模式示例詳解
這篇文章主要為大家介紹了Golang?WorkerPool線程池并發(fā)模式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08Golang教程之不可重入函數(shù)的實(shí)現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于Golang教程之不可重入函數(shù)的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09go數(shù)據(jù)結(jié)構(gòu)和算法BitMap原理及實(shí)現(xiàn)示例
這篇文章主要為大家介紹了go數(shù)據(jù)結(jié)構(gòu)和算法BitMap原理及實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07go語(yǔ)言中數(shù)據(jù)接口set集合的實(shí)現(xiàn)
set集合是一種常見(jiàn)的數(shù)據(jù)結(jié)構(gòu),它代表了一個(gè)唯一元素的集合,本文主要介紹了set的基本特性,包括唯一性、無(wú)序性、可變性和集合運(yùn)算,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-10-10利用Go語(yǔ)言實(shí)現(xiàn)Raft日志同步
這篇文章主要為大家詳細(xì)介紹了如何利用Go語(yǔ)言實(shí)現(xiàn)Raft日志同步,文中的示例代碼講解詳細(xì),對(duì)我們深入了解Go語(yǔ)言有一定的幫助,需要的可以參考一下2023-05-05在Colaboratory上運(yùn)行Go程序的詳細(xì)過(guò)程
這篇文章主要介紹了在Colaboratory上運(yùn)行Go程序,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08