【译】protobuf语法指南

一、写在前面

使用protobuf一年多的时间,使用过C++版和python的接口,发现使用过程中还会遇到一些问题,本想自己总结一下,但是想想,自己怎么总结也没有官方的权威,这里根据protobuf官网翻译总结整理一下protobuf的语法,以方便自己查询,也可以给需要的人提供一些帮助。如果你英文还可以的话,还是建议你参考官方文档。如果英文不好,更要尝试锻炼一下英文的能力。

二、protobuf指南 (proto3)

定义消息类型-Defining A Message Type
标量值类型-Scalar Value Types
默认值-Default Values
枚举-Enumerations
使用其他消息类型-Using Other Message Types
嵌套类型-Nested Types
更新消息类型-Using Other Message Types
未知字段-Unknown Fields
任何-Any
一个-Oneof
地图-Maps
包-Packages
定义服务-Defining Services
JSON 映射-JSON Mapping
选项-Options
生成访问类-Generating Your Classes

本指南介绍了如何使用protocol buffer language 来构建协议缓冲区数据,包括.proto文件语法以及如何从.proto文件生成数据访问类。它涵盖了protocol buffer的proto3版本:有关proto2语法的信息,请参阅Proto2 语言指南。这是一个参考指南 - 有关使用本文档中描述的许多功能的分步示例,请参阅所选语言的教程(目前仅适用于 proto2;更多 proto3 文档即将推出)。

1、定义消息类型-Defining A Message Type

首先让我们看一个非常简单的例子。假设要定义搜索请求消息格式,其中每个搜索请求都有一个查询字符串、感兴趣的特定结果页面以及每页的多个结果。这是.proto用来定义消息类型的文件。

syntax = "proto3";
message SearchRequest 
{
     
    string query = 1;  
    int32 page_number = 2;  
    int32 result_per_page = 3;
}

第一行指定使用proto3语法:如果不这样做,protocol buffer编译器将假定使用的是proto2,这必须是文件的第一个非空、非注释行。SearchRequest消息定义指定了三个字段(名称/值对),每个字段都有一个名称和一个类型。

指定字段类型
在上面的例子中,所有的字段都是标量类型:两个整数(page_number和result_per_page)和一个字符串(query)。但是,也可以为字段指定复合类型,包括枚举和其他消息类型。

分配字段编号
消息定义中的每个字段都有一个唯一的编号。这些字段编号用于在消息二进制格式中标识你的字段,一旦消息类型被使用,就不应更改。

请注意:1 到 15 范围内的字段编号占用一个字节进行编码,包括字段编号和字段类型(可以在协议缓冲区编码中找到更多相关信息),16 到 2047 范围内的字段编号占用两个字节。

因此,要为非常频繁出现的消息元素保留数字 1 到 15。记住为将来可能添加的频繁出现的元素留出一些空间。

可以指定的最小字段编号为 1,最大字段编号为 2^29 - 1 或 536,870,911。不能使用数字 【19000 到 19999】,它们是为 Protocol Buffers预留字段。

指定字段规则
消息字段修饰符必须是以下之一:

  • singular:格式正确的消息可以有零个或一个此字段(但不超过一个),这是 proto3 语法的默认字段规则。
  • repeated:该字段可以在格式良好的消息中重复任意次数(包括零次)。重复值的顺序将被保留。
    在 proto3 中,repeated标量数值类型的字段packed默认使用编码。
    可以packed在Protocol Buffer Encoding 中找到有关编码的更多信息。

添加更多消息类型
可以在单个.proto文件中定义多种消息类型。如果要定义多个相关消息, 例如,如果想定义与SearchResponse消息类型相对应的回复消息格式,可以将其添加到相同的.proto:

message SearchRequest 
{
     
    string query = 1;  
    int32 page_number = 2;  
    int32 result_per_page = 3;
}
message SearchResponse 
{
   
 	...
}

添加评论
要向.proto文件添加注释,请使用 C/C++ 样式//和/* … */语法。

/* SearchRequest represents a search query, with pagination options to * indicate which results to include in the response. */
message SearchRequest 
{
     
    string query = 1;  
    int32 page_number = 2;  // Which page number do we want?  
    int32 result_per_page = 3;  // Number of results to return per page.
}

保留字段
通过完全删除某个字段或将其注释掉来更新消息类型,则未来的用户可以在对类型进行自己的更新时重复使用该字段编号。如果加载相同的旧版本,这可能会导致严重的问题.proto,包括数据损坏、隐私错误等。确保不会发生这种情况的一种方法是指定已删除字段的字段编号(和/或名称,这也可能导致 JSON 序列化问题)是reserved. 如果任何未来的用户尝试使用这些字段标识符,协议缓冲区编译器会抱怨。

message Foo 
{
    
     reserved 2, 15, 9 to 11;  
     reserved "foo", "bar";
 }

请注意:不能在同一reserved语句中混合使用字段名称和字段编号。

你的proto文件是怎么生成的?

当用protocolbuffer编译器来编译.proto文件时,编译器会以所选择的语言生成代码,这些消息类型,包括获取和设置字段值、将消息序列化到一个输出流中,并从一个输入流解析消息出来。

  • 对于C++编译器从每一个生成一个.h 和 .cc文件,文件中.proto描述的每个消息类型都有一个类。

  • 对于Java编译器,.java为每个消息类型生成一个带有类的文件,以及Builder用于创建消息类实例的特殊类。

  • 对于Kotlin,除了 Java 生成的代码之外,编译器还为.kt每种消息类型生成一个文件,其中包含可用于简化创建消息实例的 DSL。

  • Python有点不同——Python 编译器会生成一个模块,其中包含 中每种消息类型的静态描述符,.proto然后与元类一起使用以在运行时创建必要的 Python 数据访问类。

  • 对于Go,编译器为.pb.go文件中的每种消息类型生成一个类型的文件。

  • 对于Ruby,编译器会生成一个.rb带有 Ruby 模块的文件,包含消息类型。

  • 对于Objective-C,编译器从 each生成一个pbobjc.h 和 pbobjc.m文件,文件中.proto描述的每个消息类型都有一个类。

  • 对于C#,编译器.cs从每个.proto生成一个文件,文件中描述的每个消息类型都有一个类。

  • 对于Dart,编译器会为.pb.dart文件中的每种消息类型生成一个带有类的文件。

2、标量值类型-Scalar Value Types

标量消息字段可以具有以下类型之一——该表显示了.proto文件中指定的类型,以及自动生成的类中的相应类型:
在这里插入图片描述
在这里插入图片描述
[1] Kotlin 使用来自Java的相应类型,即使是无符号类型,以确保在混合 Java/Kotlin 代码库中的兼容性。
[2]在Java中,无符号32位和64位整数使用它们的有符号对应物表示,最高位简单地存储在符号位中。
[3]在所有情况下,为字段设置值将执行类型检查以确保其有效。
[4]64位或无符号32位整数在解码时总是表示为 long,但如果在设置字段时给出 int,则可以是 int。在所有情况下,该值必须适合设置时表示的类型。见[2]。
[5]Python 字符串在解码时表示为 unicode,但如果给出 ASCII 字符串,则可以是 str(这可能会发生变化)。
[6]64 位机器上使用整数,32 位机器上使用字符串。

3、默认值-Default Values

解析消息时,如果编码的消息不包含特定的单数元素,则解析对象中的相应字段将设置为该字段的默认值。这些默认值是特定类型的:

  • 对于string,默认值为空字符串。
  • 对于bytes,默认值为空字节。
  • 对于bool,默认值为 false。
  • 对于numeric,默认值为零。
  • 对于enums,默认值是第一个定义的 enum value,它必须是 0。
  • 对于message fields,未设置该字段,它的确切值取决于语言。
  • 重复字段的默认值为空(通常是相应语言的空列表)。

请注意,对于标量消息字段,一旦消息被解析,就无法判断字段是否明确设置为默认值(例如,布尔值是否设置为false)或根本没有设置。在定义消息类型时,应该记住这一点。例如,false如果不希望默认情况下也发生该行为,则不要设置一个布尔值来开启某些行为。还要注意的是,如果一个标消息字段被设置为默认值,该值将不会进行序列化。

4、枚举-Enumerations

当定义消

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值