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 的一种数据交换的格式,它独立于语言,独立于平台.作 ...
随机推荐
- 使用winsw将jar包注册成windows服务
使用winsw将jar包注册成windows服务 注:exe文件作用:使用winsw将jar包注册成windows服务(下载地址https://github.com/winsw/winsw/relea ...
- Lucene介绍与使用
Lucene介绍与使用 原文链接:https://blog.csdn.net/weixin_42633131/article/details/82873731 不选择使用Lucene的6大原因? 原文 ...
- ubuntu18.04下安装MySQL5.7
更新源 sudo apt update 安装mysql sudo apt install mysql-server 使用sudo mysql进入数据设置root账户的密码和权限 sudo mysql ...
- 基于java的图书管理系统
基于java的图书管理系统 项目概述 使用数组存储数据实现一个图书管理系统,完成的功能有增加图书.删除图书.更新图书.查询图书.图书列表.增删改查 登陆注册 首页 图书更新 图书列表 开发工具/技术 ...
- Java Reactive Programming
Java Reactive Programming 响应式编程 在 Spring Boot 中,支持了响应式编程,带来了性能和内存使用方面的优化. 详见: Spring: Blocking vs no ...
- 【Azure API 管理】APIM不能连接到 App Service (APIM cannot connect to APP service)
问题描述 APIM 无法正确连接到App Service,返回500错误: { "statusCode": 500, "message": "Inte ...
- Java 常用类 于 StringBuffer 和 StringBuilder的使用 + String三者的异同
1 package com.bytezero.stringclass; 2 3 import org.junit.Test; 4 5 /** 6 * 关于 StringBuffer 和 StringB ...
- vue3在typescript下对props类型判断
使用vue3.0 对 props 进行复杂类型验证的时候,可以直接用 PropType 进行强制转换: callback: Function as PropType<()=>void> ...
- vue和xml复习
复习 JS知识梳理 JS定义的位置 行内js(事件名="javascript:js代码"),内部js(
- win10 vscode 设置 快捷键 ctrl + , ctrl + COMMA 与搜狗输入法 切换方法快捷键 冲突
win10 vscode 快捷键 ctrl + , ctrl + COMMA 与搜狗输入法 切换方法快捷键 冲突 没想到是在系统里面 Step. 1: 选择切换语音 Step. 2: 选择 键盘 St ...