1. 程式人生 > >Google Protobuf 3版本介紹

Google Protobuf 3版本介紹

本文編寫時, Google 官方的 protobuf 版本是3.0.0beta

下面介紹下proto3的一些細節變化

Proto3的語法變化

語法標記

這個版本的protoc的protobuf編譯器已經可以支援proto2語法和proto3的語法

如果你的proto檔案沒有新增syntax說明的話, 用這個版本的編譯器會報錯, 提示你預設proto2支援, 請新增語法標記

syntax = "proto2";

optional不需要了

只保留repeated標記陣列型別, optional和required都被去掉了

實際使用證明, required的設計確實是蛋疼, C++的除錯版會彈出assert,release版和optional也沒啥區別

map支援

map編寫格式為

map<key_type, value_type> map_field = N;
例如:
map<string, Project> projects = 3;
程式碼生成確認支援map, 這對於很多語言來說又可以偷懶了

欄位default標記不能使用了

位於proto2語法的欄位number後的[default=XX]

這個東西不能用了, 理由是:

對於同一段序列化後的資料, 如果序列化端的default和反序列化端的default描述不一樣會導致最終結果完全不一致

即: 同一個資料兩個結果, 這是不可預測的結果, 因此幹掉這個特性

不過本人覺得, 對於遊戲來說, 這個功能本身可以壓縮很多資料,雖然會有隱患

列舉預設值一定是0

proto2裡的預設值是列舉的第一個value對應的值, 不一定為0

proto3在你定義value時, 強制要求第一個值必須為0

這個修改為避免隱患還是有幫助的

泛型描述支援

any型別, 可以代表任何型別, 可以先讀進來, 再進行解析, 沒具體用, 步子跨大了怕扯到蛋

支援json序列化

這個極好, json再次被同化了

增加了多種語言支援

js, objc, ruby, C#等等

然而, C#版本的基礎runtime庫是用C# 6.0的語法寫的,這對於Unity mono祖傳2.0來說, 確實扯到蛋了,沒法用

Protobuf現在使用CMAKE做配置系統

編譯起來稍微麻煩, 還要下個被牆掉的cmake…

第三方庫裡對於proto3的變化

生成程式碼中的結構體欄位型別變化

對於proto2的檔案, 生成的go程式碼中的結構體依然使用型別指標作為預設儲存, 相容老的系統

對於proto3的檔案, 生成的go程式碼中的結構體直接使用欄位作為預設儲存, 不再使用GetXXX來作為欄位值訪問, 賦值時也無需使用proto.型別() 函式進行指標型別欄位值建立.

這個調整很是方便, 但丟失了optional判斷功能, 對應C++裡就是hasXXX的功能, 不過好歹這個邏輯現在用的不多了

這個修改大概也是配合json序列化來做的, go預設的json序列化時, 無法使用proto2生成的結構體的, 因為都是指標,無法賦值..

新版protoc-gen-go的外掛會生成descriptor的壓縮資料

新外掛會給每次生成的檔案新增這樣一段程式碼

var fileDescriptor0 = []byte{
    // 220 bytes of a gzipped FileDescriptorProto
    0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x64, 0x8f, 0xcd, 0x4e, 0xc5, 0x20,
    0x10, 0x85, 0x53, 0xbd, 0x35, 0x32, 0xb7, 0xdd, 0x4c, 0x5c, 0xb0, 0x70, 0x71, 0xd3, 0xb8, 0x70,
    0x75, 0x17, 0xfa, 0x04, 0xc6, 0xd8, 0xb8, 0x50, 0x63, 0xa8, 0x2f, 0x80, 0xed, 0x44, 0x89, 0x28,
    0x04, 0xc6, 0xbf, 0x47, 0xf1, 0x6d, 0x95, 0x49, 0x8d, 0x4d, 0x5c, 0x01, 0xdf, 0x39, 0x7c, 0x30,
    0x00, 0x1c, 0x82, 0xdf, 0xc6, 0x14, 0x38, 0xe0, 0xaa, 0xec, 0xbb, 0x37, 0x68, 0x2e, 0x3e, 0x62,
    0x48, 0x7c, 0x49, 0x76, 0xa2, 0x84, 0x47, 0xd0, 0xde, 0x96, 0xf8, 0xee, 0x33, 0xd2, 0x8d, 0x7d,
    0x26, 0x5d, 0x6d, 0xaa, 0x63, 0x65, 0xda, 0xb8, 0x84, 0xd8, 0x41, 0x63, 0xc2, 0x7b, 0xef, 0xc8,
    0x4f, 0x52, 0xda, 0x91, 0x52, 0x93, 0x16, 0x0c, 0x0f, 0x41, 0x89, 0xa9, 0x77, 0x9e, 0xf4, 0xae,
    0x14, 0x54, 0xfc, 0x05, 0xdd, 0x57, 0x05, 0x4a, 0xba, 0xd7, 0xc4, 0x16, 0xb7, 0x80, 0x03, 0x27,
    0xf7, 0xf2, 0x70, 0x72, 0xe5, 0x32, 0x0f, 0xd1, 0x3b, 0xa6, 0x34, 0x5b, 0x31, 0xff, 0x4b, 0x70,
    0x03, 0x6b, 0x43, 0x91, 0x2c, 0x9f, 0x3f, 0xd2, 0xf8, 0x24, 0xf6, 0x7d, 0xb3, 0x4e, 0x7f, 0x08,
    0x0f, 0xa0, 0x3e, 0xf3, 0xce, 0x66, 0xbd, 0x12, 0x49, 0x6d, 0xcb, 0xa1, 0x4c, 0x37, 0xbf, 0xf3,
    0xb3, 0xbc, 0x8e, 0xac, 0x6b, 0xb9, 0xd9, 0xe6, 0x25, 0xbc, 0xdf, 0x93, 0x6f, 0x9e, 0x7e, 0x07,
    0x00, 0x00, 0xff, 0xff, 0x0c, 0x9f, 0x10, 0xa8, 0x2e, 0x01, 0x00, 0x00,
}

對於meta資訊的提取還是很方便的

然而

對於多個檔案的生成, 這樣做非常的麻煩, 因為這個欄位會重複導致編譯錯誤

很多人在論壇裡吐槽, 官方給出的解決方法是, 使用protoc一次性傳入一個package下的所有的proto直接生成一個go

而不是現在的一個proto一個go

生成程式碼會自動註冊到全域性, 並可以方便的查詢

以前這個程式碼需要自己來做, 現在官方提供了支援, 很是方便

然而, 為什麼不支援遍歷… 殘念啊, 又要自己動手了