本文編寫時(shí), Google 官方的 protobuf 版本是3.0.0beta
下面介紹下proto3的一些細(xì)節(jié)變化
Proto3的語(yǔ)法變化
語(yǔ)法標(biāo)記
這個(gè)版本的protoc的protobuf編譯器已經(jīng)可以支持proto2語(yǔ)法和proto3的語(yǔ)法
如果你的proto文件沒(méi)有添加syntax說(shuō)明的話, 用這個(gè)版本的編譯器會(huì)報(bào)錯(cuò), 提示你默認(rèn)proto2支持, 請(qǐng)?zhí)砑诱Z(yǔ)法標(biāo)記
syntax = "proto2";
optional不需要了
只保留repeated標(biāo)記數(shù)組類型, optional和required都被去掉了
實(shí)際使用證明, required的設(shè)計(jì)確實(shí)是蛋疼, C++的調(diào)試版會(huì)彈出assert,release版和optional也沒(méi)啥區(qū)別
map支持
map編寫格式為
map<key_type, value_type> map_field = N;
例如:
map<string, Project> projects = 3;
代碼生成確認(rèn)支持map, 這對(duì)于很多語(yǔ)言來(lái)說(shuō)又可以偷懶了
字段default標(biāo)記不能使用了
位于proto2語(yǔ)法的字段number后的[default=XX]
這個(gè)東西不能用了, 理由是:
對(duì)于同一段序列化后的數(shù)據(jù), 如果序列化端的default和反序列化端的default描述不一樣會(huì)導(dǎo)致最終結(jié)果完全不一致
即: 同一個(gè)數(shù)據(jù)兩個(gè)結(jié)果, 這是不可預(yù)測(cè)的結(jié)果, 因此干掉這個(gè)特性
不過(guò)本人覺(jué)得, 對(duì)于游戲來(lái)說(shuō), 這個(gè)功能本身可以壓縮很多數(shù)據(jù),雖然會(huì)有隱患
枚舉默認(rèn)值一定是0
proto2里的默認(rèn)值是枚舉的第一個(gè)value對(duì)應(yīng)的值, 不一定為0
proto3在你定義value時(shí), 強(qiáng)制要求第一個(gè)值必須為0
這個(gè)修改為避免隱患還是有幫助的
泛型描述支持
any類型, 可以代表任何類型, 可以先讀進(jìn)來(lái), 再進(jìn)行解析, 沒(méi)具體用, 步子跨大了怕扯到蛋
支持json序列化
這個(gè)極好, json再次被同化了
增加了多種語(yǔ)言支持
js, objc, ruby, C#等等
然而, C#版本的基礎(chǔ)runtime庫(kù)是用C# 6.0的語(yǔ)法寫的,這對(duì)于Unity mono祖?zhèn)?.0來(lái)說(shuō), 確實(shí)扯到蛋了,沒(méi)法用
Protobuf現(xiàn)在使用CMAKE做配置系統(tǒng)
編譯起來(lái)稍微麻煩, 還要下個(gè)被墻掉的cmake…
第三方庫(kù)里對(duì)于proto3的變化
Golang的官方protobuf支持: https://github.com/golang/protobuf
生成代碼中的結(jié)構(gòu)體字段類型變化
對(duì)于proto2的文件, 生成的go代碼中的結(jié)構(gòu)體依然使用類型指針作為默認(rèn)存儲(chǔ), 兼容老的系統(tǒng)
對(duì)于proto3的文件, 生成的go代碼中的結(jié)構(gòu)體直接使用字段作為默認(rèn)存儲(chǔ), 不再使用GetXXX來(lái)作為字段值訪問(wèn), 賦值時(shí)也無(wú)需使用proto.類型() 函數(shù)進(jìn)行指針類型字段值創(chuàng)建.
這個(gè)調(diào)整很是方便, 但丟失了optional判斷功能, 對(duì)應(yīng)C++里就是hasXXX的功能, 不過(guò)好歹這個(gè)邏輯現(xiàn)在用的不多了
這個(gè)修改大概也是配合json序列化來(lái)做的, go默認(rèn)的json序列化時(shí), 無(wú)法使用proto2生成的結(jié)構(gòu)體的, 因?yàn)槎际侵羔?無(wú)法賦值..
新版protoc-gen-go的插件會(huì)生成descriptor的壓縮數(shù)據(jù)
新插件會(huì)給每次生成的文件添加這樣一段代碼
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,
}
對(duì)于meta信息的提取還是很方便的
然而
對(duì)于多個(gè)文件的生成, 這樣做非常的麻煩, 因?yàn)檫@個(gè)字段會(huì)重復(fù)導(dǎo)致編譯錯(cuò)誤
很多人在論壇里吐槽, 官方給出的解決方法是, 使用protoc一次性傳入一個(gè)package下的所有的proto直接生成一個(gè)go
而不是現(xiàn)在的一個(gè)proto一個(gè)go
生成代碼會(huì)自動(dòng)注冊(cè)到全局, 并可以方便的查詢
以前這個(gè)代碼需要自己來(lái)做, 現(xiàn)在官方提供了支持, 很是方便
然而, 為什么不支持遍歷… 殘念啊, 又要自己動(dòng)手了