网易首页 > 网易号 > 正文 申请入驻

protocol buffer没那么难,不信你看这篇

0
分享至

简介

上一篇文章我们对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 map_field = N;

这里的value_type可以是除map之外的任意类型。注意map不能是repeated。

map中的数据的顺序是不定的,我们不能依赖存入的map顺序来判断其取出的顺序。

总结

以上就是proto3中定义声明文件该注意的事项了,大家在使用protobuf的时候要多加注意。

本文已收录于 http://www.flydean.com/02-protocolbuf-detail/

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
中央社会工作部:坚决拥护党中央决定

中央社会工作部:坚决拥护党中央决定

新京报
2026-06-28 09:21:39
切尔西官方:与曼城、马雷斯卡达成和解协议,将获得赔偿金

切尔西官方:与曼城、马雷斯卡达成和解协议,将获得赔偿金

懂球帝
2026-06-29 21:09:58
中国运气有多好?低调收回被侵占的领土,还意外发现大量珍稀矿藏

中国运气有多好?低调收回被侵占的领土,还意外发现大量珍稀矿藏

黄丽搞笑小能手
2026-06-29 10:55:46
为什么高考本科线只有400多分,却有一大半学生根本考不上本科?

为什么高考本科线只有400多分,却有一大半学生根本考不上本科?

娱乐的宅急便
2026-06-28 08:40:23
接到求援后,中美动作都很快,美军舰船飞机同步出动,事态严重了

接到求援后,中美动作都很快,美军舰船飞机同步出动,事态严重了

风雨与阳光
2026-06-29 11:38:33
高市早苗紧急记者会上口齿不清,被质疑醉酒

高市早苗紧急记者会上口齿不清,被质疑醉酒

环球时报国际
2026-06-29 14:24:53
华盛顿带娇妻中国行,西湖游船很浪漫,拿9000万逆袭,未来可期

华盛顿带娇妻中国行,西湖游船很浪漫,拿9000万逆袭,未来可期

大西体育
2026-06-29 10:23:10
有人60岁就脑梗,有人一辈子不会脑梗,医生直言:关键在于5件事

有人60岁就脑梗,有人一辈子不会脑梗,医生直言:关键在于5件事

健身狂人
2026-06-26 02:16:28
以色列现在才恍然大悟,发现自己上当了,可惜已经来不及了

以色列现在才恍然大悟,发现自己上当了,可惜已经来不及了

农夫史记
2026-06-28 20:53:52
刚刚,比亚迪官宣:新车18.88万起!

刚刚,比亚迪官宣:新车18.88万起!

手机评测室
2026-06-29 12:07:47
寡头逼普京按核按钮,俄媒内部自己都怕了:中国翻脸比核弹更致命

寡头逼普京按核按钮,俄媒内部自己都怕了:中国翻脸比核弹更致命

而长终
2026-06-29 21:15:30
1962年毛岸青回乡祭拜母亲,欲下跪遭妻子制止,顿时明白妻子用意

1962年毛岸青回乡祭拜母亲,欲下跪遭妻子制止,顿时明白妻子用意

史论人生
2026-06-29 21:10:05
惊现“小六”!运-20最新大片彩蛋引爆全网

惊现“小六”!运-20最新大片彩蛋引爆全网

看看新闻Knews
2026-06-28 15:32:05
她用AI穿越回泰坦尼克号沉船当晚,240万人看哭了

她用AI穿越回泰坦尼克号沉船当晚,240万人看哭了

新智元
2026-06-28 15:10:40
A股分红派息转增一览:63股今日股权登记

A股分红派息转增一览:63股今日股权登记

每日经济新闻
2026-06-29 08:07:06
辽宁一县城,为何活出内蒙古气质?

辽宁一县城,为何活出内蒙古气质?

小蜜情感说
2026-06-29 18:28:03
我爸97看起来才60,长寿秘诀不是多走路多吃保健品,而是这四件事

我爸97看起来才60,长寿秘诀不是多走路多吃保健品,而是这四件事

蝉吟槐蕊
2026-06-28 05:16:03
扣船扣人整整10天,对岸这次真把大陆惹毛了!四项反制招招硬核

扣船扣人整整10天,对岸这次真把大陆惹毛了!四项反制招招硬核

音乐时光的娱乐
2026-06-29 18:51:30
俄强硬派主张动用核武?普京对乌让步,提议互相停止越境纵深打击

俄强硬派主张动用核武?普京对乌让步,提议互相停止越境纵深打击

春之韵
2026-06-29 19:44:43
59岁周立波近况:成也一张嘴,败也一张嘴,长期定居美国依旧潇洒

59岁周立波近况:成也一张嘴,败也一张嘴,长期定居美国依旧潇洒

品茗赏娱
2026-06-28 19:35:06
2026-06-29 21:51:00
flydean程序那些事
flydean程序那些事
最通俗的解读,最深刻的干货!
356文章数 438关注度
往期回顾 全部

科技要闻

杀疯了!深圳一天出两家200亿具身智能公司

头条要闻

美从俄乌战场抽身 金灿荣:美国有个大战略目标已完成

头条要闻

美从俄乌战场抽身 金灿荣:美国有个大战略目标已完成

体育要闻

他和伊朗队,再次赢得全世界的尊重

娱乐要闻

跟风电影《给阿公的牛肉丸》开机

财经要闻

万达广场批量易主 多位投资人正式入局

汽车要闻

全新宝马iX3长轴版将于成都车展预售 四季度交付

态度原创

教育
健康
亲子
手机
军事航空

教育要闻

又一在线教育头部选手,把学习搬进“闯关”里

狂吃“糯叽叽”小心肠梗阻!

亲子要闻

怀孕适合吃哪个品牌的燕窝?—2026十大品牌孕期安全评测,放心选

手机要闻

vivo黄韬:X Fold6要做用户唯一主力机

军事要闻

普京最新发声:俄罗斯正处于命运攸关之际

无障碍浏览 进入关怀版