本文編寫時, 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的變化
Golang的官方protobuf支持: https://github.com/golang/protobuf
生成代碼中的結構體字段類型變化
對于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
生成代碼會自動注冊到全局, 并可以方便的查詢
以前這個代碼需要自己來做, 現在官方提供了支持, 很是方便
然而, 為什么不支持遍歷… 殘念啊, 又要自己動手了