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 的一种数据交换的格式,它独立于语言,独立于平台.作 ...
随机推荐
- 狂神说Git学习笔记整理
Git 版本控制 在开发过程中,项目会进行版本迭代,新版本会取代旧版本,但是我们不希望直接删除旧版本,所以就需要一个版本管理器来管理新旧版本,不然就是手动控制... 多人开发必须使用版本控制!!! ...
- 解析Spring中的循环依赖问题:再探三级缓存(AOP)
前言 在之前的内容中,我们简要探讨了循环依赖,并指出仅通过引入二级缓存即可解决此问题.然而,你可能会好奇为何在Spring框架中还需要引入三级缓存singletonFactories.在前述总结中,我 ...
- Excel Undo-Redo的编程问题
Excel Undo历史栈对外是不透明的. 代码对Excel表单的编辑操作会清空Excel内部的Undo历史. Application.OnUndo只支持一次撤销,并且不支持ReDo. 使用DDE的方 ...
- Nebula Importer 数据导入实践
本文首发于 Nebula Graph Community 公众号 前言 Nebula 目前作为较为成熟的产品,已经有着很丰富的生态.数据导入的维度而言就已经提供了多种选择.有大而全的Nebula Ex ...
- C++ STL容器 set类型
C++ STL容器 set类型 set是C++引入的二叉树数据结构 特点: 自动将元素排序 插入和删除查找logn 必须元素支持严格的弱顺序 不能改变元素的值 代码 using Group = std ...
- 分组聚合不再难:Pandas groupby使用指南
处理大量数据时,经常需要对数据进行分组和汇总,groupby为我们提供了一种简洁.高效的方式来实现这些操作,从而简化了数据分析的流程. 1. 分组聚合是什么 分组是指根据一个或多个列的值将数据分成多个 ...
- C#---串口调试助手
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 usin ...
- [.Net]使用Soa库+Abp搭建微服务项目框架(五):服务发现和健康监测
上篇文章说过,服务发现和健康监测是面向服务体系架构重要的模块,Soa库可以配置使用Consul作为服务发现服务,或者轮询已配置的服务列表作为本机服务发现. 将用Hangfire来作为服务发现与健康监 ...
- react中css里面 class中的 图片的相对地址 完美解决 backgroundImage
发现问题:缓存 之前react的图片,也在style里面,也无所谓. 刚做了一个输入框,change的时候改变图片,每次都刷新图片,关键是没缓存,这哪受得了 之前用的: 网上搜索各种插件,替换什么的, ...
- Java的Class类,注解与反射
Class对象: 我们每创建一个类,经过build都会生成对应的.class文件 该类无法只能由虚拟机创建对象,其构造函数为private 当我们创建某个类的对象,ClassLoader(一个类)就会 ...