protocol buffer没那么难,不信你看这篇
简介
上一篇文章我们对google的protobuf已经有了一个基本的认识,并且能够使用相应的工具生成对应的代码了。但是对于.proto文件的格式和具体支持的类型还不是很清楚。今天本文将会带大家一探究竟。
注意,本文介绍的协议是proto3版本的。
定义一个消息
protobuf中的主体被称为是message,可以将其看做是我们在程序中定义的类。我们可以在.proto文件中定义这个message对象,并且为其添加属性,如下所示:
syntax = "proto3";
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
上例的第一行指定了.proto文件的协议类型,这里使用的是proto3,也是最新版的协议,如果不指定,默认情况下是proto2。
类型定义
这里我们为SearchRequest对象,定义了三个属性,其类型分别是String和int32。
String和int32都是简单类型,protobuf支持的简单类型如下:
protobuf类型 | 说明 | 对应的java类型 |
---|---|---|
double | 双精度浮点类型 | double |
float | 浮点类型 | float |
int32 | 整型数字,最好不表示负数 | int |
int64 | 整型数字,最好不表示负数 | long |
uint32 | 无符号整数 | int |
uint64 | 无符号整数 | long |
sint32 | 带符号整数 | int |
sint64 | 带符号整数 | long |
fixed32 | 四个字节的整数 | int |
fixed64 | 8个字节的整数 | long |
sfixed32 | 4个字节的带符号整数 | int |
sfixed64 | 8个字节的带符号整数 | long |
bool | 布尔类型 | boolean |
string | 字符串 | String |
bytes | 字节 | ByteString |
当然protobuf还支持复杂的组合类型和枚举类型。
枚举类型在protobuf中用enum来表示,我们来看一个枚举类型的定义:
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
enum Corpus {
UNIVERSAL = 0;
WEB = 1;
IMAGES = 2;
LOCAL = 3;
NEWS = 4;
PRODUCTS = 5;
VIDEO = 6;
}
Corpus corpus = 4;
}
上面我们定义了一个枚举类型Corpus,枚举类型中定义的枚举值是从0开始的,0也是枚举类型的默认值。
在枚举中,还可以定义具有相同value的枚举类型,但是这样需要加上allow_alias=true的选项,如下所示:
message MyMessage1 {
enum EnumAllowingAlias {
option allow_alias = true;
UNKNOWN = 0;
STARTED = 1;
RUNNING = 1;
}
}
message MyMessage2 {
enum EnumNotAllowingAlias {
UNKNOWN = 0;
STARTED = 1;
// RUNNING = 1; // Uncommenting this line will cause a compile error inside Google and a warning message outside.
}
}
在枚举类型中,如果我们后续对某些枚举类型进行了删除,那么被删除的值可能会被后续的用户使用,这样就会造成潜在的代码隐患,为了解决这个问题,枚举提供了一个reserved的关键词,被这个关键词声明的枚举类型,就不会被后续使用,如下所示:
enum Foo {
reserved 2, 15, 9 to 11, 40 to max;
reserved "FOO", "BAR";
}
reserved关键字也可以用在message的字段中,表示后续不要使用到这些字段,如下:
message Foo {
reserved 2, 15, 9 to 11;
reserved "foo", "bar";
}
字段的值
我们可以看到,每个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 SearchRequest {
string query = 1;
int32 page_number = 2; // 页面的number
int32 result_per_page = 3; // 每页的结果
}
嵌套类型
在一个message中还可以嵌入一个message,如下所示:
message SearchResponse {
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}
repeated Result results = 1;
}
在上例中,我们在SearchResponse定义了一个Result类型,在java中,实际上可以将其看做是嵌套类。
如果希望在message的定义类之外使用这个内部的message,则可以通过_Parent_._Type_来
定义:
message SomeOtherMessage {
SearchResponse.Result result = 1;
}
嵌套类型可以任意嵌套,如下所示:
message Outer { // Level 0
message MiddleAA { // Level 1
message Inner { // Level 2
int64 ival = 1;
bool booly = 2;
}
}
message MiddleBB { // Level 1
message Inner { // Level 2
int32 ival = 1;
bool booly = 2;
}
}
}
Map
如果想要在proto中定义map,可以这样写:
map<key_type, value_type> map_field = N;
这里的value_type可以是除map之外的任意类型。注意map不能是repeated。
map中的数据的顺序是不定的,我们不能依赖存入的map顺序来判断其取出的顺序。
总结
以上就是proto3中定义声明文件该注意的事项了,大家在使用protobuf的时候要多加注意。
本文已收录于 http://www.flydean.com/02-protocolbuf-detail/
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
protocol buffer没那么难,不信你看这篇的更多相关文章
- Google Protocol Buffer 简单介绍
以下内容主要整理自官方文档. 为什么使用 Protocol Buffers .proto文件 Protocol Buffers 语法 编译.proto文件 Protocol Buffers API 枚 ...
- 快来看看Google出品的Protocol Buffer,别仅仅会用Json和XML了
前言 习惯用 Json.XML 数据存储格式的你们,相信大多都没听过Protocol Buffer Protocol Buffer 事实上 是 Google出品的一种轻量 & 高效的结构化数据 ...
- Protocol Buffer技术详解(数据编码)
Protocol Buffer技术详解(数据编码) 之前已经发了三篇有关Protocol Buffer的技术博客,其中第一篇介绍了Protocol Buffer的语言规范,而后两篇则分别基于C++和J ...
- google protocol buffer -2-.proto 定义规则
essage为主要关键字,类似于java中的class.定义简单message类型 SearchRequest.proto定义了每个查询请求的消息格式,每个请求都会有查询关键词query,查询结果的页 ...
- php实现把数组排成最小的数(核心是排序)(看别人的代码其实也没那么难)(把php代码也看一下)(implode("",$numbers);)(usort)
php实现把数组排成最小的数(核心是排序)(看别人的代码其实也没那么难)(把php代码也看一下)(implode("",$numbers);)(usort) 一.总结 核心是排序 ...
- 从零开始山寨Caffe·伍:Protocol Buffer简易指南
你为Class外访问private对象而苦恼嘛?你为设计序列化格式而头疼嘛? ——欢迎体验Google Protocol Buffer 面向对象之封装性 历史遗留问题 面向对象中最矛盾的一个特性,就是 ...
- Google Protocol Buffer的安装与.proto文件的定义
什么是protocol Buffer呢? Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准. 我理解的就是:它是一种轻便高效的结构 ...
- Corba、protocol buffer、SOA的区别 (转)
From: http://www.zhihu.com/question/20279489 Google的protocol buffers?这个跟corba.soa没啥关系,不同层次的概念,没法比.pr ...
- protocol buffer和当年corba ,和现在SOA有啥异同点
CORBA是对象管理集团(OMG)的一个标准,使得不同语言编写的,运行在不同计算机上的能够协同工作.标准包括分布式计算的通讯协议(GIOP和IIOP),可映射到多种语言的接口描述语言(IDL),对象请 ...
- Google的Protocol Buffer格式分析
[转]转自:序列化笔记之一:Google的Protocol Buffer格式分析 从公开介绍来看,ProtocolBuffer(PB)是google 的一种数据交换的格式,它独立于语言,独立于平台.作 ...
随机推荐
- pexpect模块(替代subprocess)
https://blog.csdn.net/pcn01/article/details/104993742/
- 将模型对象转换为json字典:model_to_dict
例子 from rest_framework.views import APIView class StudentAPIView(APIView): def get(self, request): p ...
- 浅入 ABP 系列教程目录汇总
浅入ABP(1):搭建基础结构的 ABP 解决方案 https://www.cnblogs.com/whuanle/p/13675889.html 浅入ABP(2):添加基础集成服务 https:// ...
- redis迁移同步工具-redis-shake
官方文档: https://github.com/alibaba/RedisShake/wiki/快速开始:数据迁移 下载: https://github.com/alibaba/RedisShake ...
- 使用C#和MemoryCache组件实现轮流调用APIKey以提高并发能力
文章信息 标题:使用C#和MemoryCache组件实现轮流调用API Key以提高并发能力的技巧 摘要:本文介绍了如何利用C#语言中的MemoryCache组件,结合并发编程技巧,实现轮流调用多个A ...
- 面试官问我会ES么,我说不会,抓紧学起【ES(一)聚合分析篇】
ES聚合分析 1.metric(指标)聚合 1.1 单值分析 min 求指定字段的最小值 # 求价格的最小值 { "size":0, "aggs":{ &quo ...
- Vite + Vue3.0 项目初始化
主要是冷启动,实际中项目非常庞大,现在1w的笔记本,每次冷启动,也得等一下,所以准备转型 Vite+Vue3.0,毕竟Vite不支持Vue2.0,这就只能下个项目的时候再启动了. $ npm init ...
- c 的头文件标准格式
前记: C语言的头文件是嵌入式系统中常用的,也是很多人没有注意的,但是写的很差的,这里给出一个经典的模板,仅供参考. 正文: 经典的格式: /***************************** ...
- day03-功能实现03
功能实现03 9.功能08-分页显示 9.1需求分析 将查询的数据进行分页显示,要求功能如下: 显示共多少条记录 可以设置每页显示几条 点击第几页,显示对应的数据 9.2思路分析 后端使用MyBati ...
- Linux 文件权限、VIM、防火墙
Linux 文件权限.VIM.防火墙 目录 Linux 文件权限.VIM.防火墙 SSH连接 环境变量 权限 更改文件所属 更改文件权限 su和sudo 包管理器 VI/VIM iptables防火墙 ...