简介

上一篇文章我们对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没那么难,不信你看这篇的更多相关文章

  1. Google Protocol Buffer 简单介绍

    以下内容主要整理自官方文档. 为什么使用 Protocol Buffers .proto文件 Protocol Buffers 语法 编译.proto文件 Protocol Buffers API 枚 ...

  2. 快来看看Google出品的Protocol Buffer,别仅仅会用Json和XML了

    前言 习惯用 Json.XML 数据存储格式的你们,相信大多都没听过Protocol Buffer Protocol Buffer 事实上 是 Google出品的一种轻量 & 高效的结构化数据 ...

  3. Protocol Buffer技术详解(数据编码)

    Protocol Buffer技术详解(数据编码) 之前已经发了三篇有关Protocol Buffer的技术博客,其中第一篇介绍了Protocol Buffer的语言规范,而后两篇则分别基于C++和J ...

  4. google protocol buffer -2-.proto 定义规则

    essage为主要关键字,类似于java中的class.定义简单message类型 SearchRequest.proto定义了每个查询请求的消息格式,每个请求都会有查询关键词query,查询结果的页 ...

  5. php实现把数组排成最小的数(核心是排序)(看别人的代码其实也没那么难)(把php代码也看一下)(implode("",$numbers);)(usort)

    php实现把数组排成最小的数(核心是排序)(看别人的代码其实也没那么难)(把php代码也看一下)(implode("",$numbers);)(usort) 一.总结 核心是排序 ...

  6. 从零开始山寨Caffe·伍:Protocol Buffer简易指南

    你为Class外访问private对象而苦恼嘛?你为设计序列化格式而头疼嘛? ——欢迎体验Google Protocol Buffer 面向对象之封装性 历史遗留问题 面向对象中最矛盾的一个特性,就是 ...

  7. Google Protocol Buffer的安装与.proto文件的定义

    什么是protocol Buffer呢? Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准. 我理解的就是:它是一种轻便高效的结构 ...

  8. Corba、protocol buffer、SOA的区别 (转)

    From: http://www.zhihu.com/question/20279489 Google的protocol buffers?这个跟corba.soa没啥关系,不同层次的概念,没法比.pr ...

  9. protocol buffer和当年corba ,和现在SOA有啥异同点

    CORBA是对象管理集团(OMG)的一个标准,使得不同语言编写的,运行在不同计算机上的能够协同工作.标准包括分布式计算的通讯协议(GIOP和IIOP),可映射到多种语言的接口描述语言(IDL),对象请 ...

  10. Google的Protocol Buffer格式分析

    [转]转自:序列化笔记之一:Google的Protocol Buffer格式分析 从公开介绍来看,ProtocolBuffer(PB)是google 的一种数据交换的格式,它独立于语言,独立于平台.作 ...

随机推荐

  1. Counter函数

    构造一个空Counter import collections c = collections.Counter() c.update('abcdaab') print(c) # Counter({'a ...

  2. 聊聊图数据库和图数据库的小知识 Vol.02

    2010 年前后,对于社交媒体网络研究的兴起带动了图计算的大规模应用. 2000 年前后热门的是 信息检索 和 分析 ,主要是 Google 的带动,以及 Amazon 的 e-commerce 所用 ...

  3. 今天接到一个根据excel来更新数据库的需求,用php写个小脚本

    需求大概内容是,excel中有些条目需要删除.有些需要新增,就需要基于这份excel生成删.增的SQL. 要求是这样的:蓝色要删除的,黄色是要新增的,白色和灰色的不用管. 我第一时间就在想:还得识别单 ...

  4. C#实现图片对比

    前言 虽然已经正式转JAVA了,但最近发现一个特别好的开源项目masuit,不仅提供很多简便的功能,还有图像的一些特殊操作功能. 下面就实现一个简单图像对比. 实现对比 代码如下,实现一个可以对比翻转 ...

  5. 从零开始写 Docker(四)---使用 pivotRoot 切换 rootfs 实现文件系统隔离

    change-rootfs-by-pivot-root.png 本文为从零开始写 Docker 系列第四篇,在mydocker run 基础上使用 pivotRoot 系统调用切换 rootfs 实现 ...

  6. Java 常用类 String的常用方法(3)

    1 /** 2 * String常用方法3 3 * 替换: 4 * String replace(char oldChar,char newChar): 返回一个新的字符串,它是通过 5 * 用new ...

  7. Java 对属性赋值的位置 执行的先后顺序

    1 package com.bytezreo.block; 2 3 /** 4 * 5 * @Description 对属性赋值的位置: 6 * @author Bytezero·zhenglei! ...

  8. springMvc精简整理

    精简共分步 新建一个web工程  导入核心就二包,因为springmvc 包自己有依赖 <?xml version="1.0" encoding="UTF-8&qu ...

  9. Java-Script 编程

    Java-Script 编程 目录 Java-Script 编程 一. Js概念 1.1 简介 1.2 语法结构 二. 变量使用 2.1 定义变量 2.2 定义常量 三. 数据类型 3.1 数值类型( ...

  10. InputRegZen.vue 正则Input 限制输入框输入内容

    核心内容 已经 perfect,没有用外库,原生完成 用的 iview的Input组件 封装 // InputRegZen.vue <template> <div> <I ...