protocol buffer 没那么难, 不信你看这篇
简介
上一篇文章我们对 google 的 protobuf 已经有了一个基本的认识,并且能够使用相应的工具生成对应的代码了。但是对于.proto 文件的格式和具体支持的类型还不是很清楚。今天本文将会带大家一探究竟。
注意,本文介绍的协议是 proto3 版本的。
定义一个消息
protobuf 中的主体被称为是 message,可以将其看做是我们在程序中定义的类。我们可以在.proto 文件中定义这个 message 对象,并且为其添加属性,如下所示:
上例的第一行指定了.proto 文件的协议类型,这里使用的是 proto3,也是最新版的协议,如果不指定,默认情况下是 proto2。
类型定义
这里我们为 SearchRequest 对象,定义了三个属性,其类型分别是 String 和 int32。
String 和 int32 都是简单类型,protobuf 支持的简单类型如下:
当然 protobuf 还支持复杂的组合类型和枚举类型。
枚举类型在 protobuf 中用 enum 来表示,我们来看一个枚举类型的定义:
上面我们定义了一个枚举类型 Corpus,枚举类型中定义的枚举值是从 0 开始的,0 也是枚举类型的默认值。
在枚举中,还可以定义具有相同 value 的枚举类型,但是这样需要加上 allow_alias=true 的选项,如下所示:
在枚举类型中,如果我们后续对某些枚举类型进行了删除,那么被删除的值可能会被后续的用户使用,这样就会造成潜在的代码隐患,为了解决这个问题,枚举提供了一个 reserved 的关键词,被这个关键词声明的枚举类型,就不会被后续使用,如下所示:
reserved 关键字也可以用在 message 的字段中,表示后续不要使用到这些字段,如下:
字段的值
我们可以看到,每个 message 的字段都分配了一个值,每个字段的值在 message 中都是唯一的,这些值是用来定位在二进制消息格式中的字段位置。所以一旦定义之后,不要随意修改。
要注意的是值 1-15 在二进制中使用的 1 个字节来表示的,值 16-2047 需要使用 2 个字节来表示,所以通常将 1-15 使用在最常见的字段和可能重复的字段,这样可以节约编码后的空间。
最小的值是 1,最大的值是 2 的 29 次方-1,或者 536,870,911。这中间从 19000-19999 是保留数字,不能使用。
当消息被编译之后,各个字段将会被转成为对应的类型,并且各个字段类型将会被赋予不同的初始值。
strings 的默认值是空字符串,bytes 的默认值是空 bytes,bools 的默认值是 false,数字类型的默认值是 0,枚举类型的默认值是枚举的第一个元素。
字段描述符
每个消息的字段都可以有两种描述符,第一种叫做 singular,表示 message 中可以有 0 个或者 1 个这个字段,这是 proto3 中默认的定义方式。
第二种叫做 repeated,表示这个字段在 message 中是可以重复的,也就是说它代表的是一个集合。
添加注释
在 proto 中的注释和 C++的风格类似,可以使用: // 或者 /* … */ 的风格来注释,如下所示:
嵌套类型
在一个 message 中还可以嵌入一个 message,如下所示:
在上例中,我们在 SearchResponse 定义了一个 Result 类型,在 java 中,实际上可以将其看做是嵌套类。
如果希望在 message 的定义类之外使用这个内部的 message,则可以通过_Parent_._Type_来
定义:
嵌套类型可以任意嵌套,如下所示:
Map
如果想要在 proto 中定义 map,可以这样写:
这里的 value_type 可以是除 map 之外的任意类型。注意 map 不能是 repeated。
map 中的数据的顺序是不定的,我们不能依赖存入的 map 顺序来判断其取出的顺序。
总结
以上就是 proto3 中定义声明文件该注意的事项了,大家在使用 protobuf 的时候要多加注意。
本文已收录于 http://www.flydean.com/02-protocolbuf-detail/
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
版权声明: 本文为 InfoQ 作者【程序那些事】的原创文章。
原文链接:【http://xie.infoq.cn/article/1e5f3df3c4c8f6e3492021a55】。文章转载请联系作者。
评论