文章目录
版本
Proto3
命名风格
字段名风格用下划线
定义一个消息类型
-
简单示例文件
example.proto
syntax = "proto3"; /* 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. } message SearchResponse { ... }
- 首行表示版本,必须放在第一行空格、没有注释!
message
表示这是一个消息结构。SearchRequest
消息名字。int32
、string
指定消息类型。- 字段后面的1、2、3 是字段标识符,存储的对象的字段都是用数字表示,而不是字段名。这样可以节省内存,速度快等特点。1-15 数字编码后占1个字节,16-2047编码后占两个字节。190000 -19999 是保留数字,不能使用。
- 字段有两种格式 :
singular
和repeated
。singular
表示该类型字段可以有零个或者一个,但不能超过一个。repeated
类似数组,表示该类型的字段零个或者多个。 - 单行注释风格 :
//
,多行注释:/* ... */
。
保留字段
当升级协议的时候,可能会删除一些旧的字段。 这样有可能新定义的字段名或者数字会和旧的代码冲突。为了兼容之前的版本或者考虑到未来的使用,有些字段名或者数字可以用 reserved
保留。
message Foo {
reserved 2, 15, 9 to 11;
reserved "foo", "bar";
}
字段类型对应不同语言的输出
.proto Type | Notes | C++ Type | Java Type | Python Type[2] | Go Type | Ruby Type | C# Type | PHP Type | Dart Type |
---|---|---|---|---|---|---|---|---|---|
double | double | double | float | float64 | Float | double | float | double | |
float | float | float | float | float32 | Float | float | float | double | |
int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | int32 | Fixnum or Bignum (as required) | int | integer | int |
int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long[3] | int64 | Bignum | long | integer/string[5] | Int64 |
uint32 | Uses variable-length encoding. | uint32 | int[1] | int/long[3] | uint32 | Fixnum or Bignum (as required) | uint | integer | int |
uint64 | Uses variable-length encoding. | uint64 | long[1] | int/long[3] | uint64 | Bignum | ulong | integer/string[5] | Int64 |
sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | int32 | Fixnum or Bignum (as required) | int | integer | int |
sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long[3] | int64 | Bignum | long | integer/string[5] | Int64 |
fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 228. | uint32 | int[1] | int/long[3] | uint32 | Fixnum or Bignum (as required) | uint | integer | int |
fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 256. | uint64 | long[1] | int/long[3] | uint64 | Bignum | ulong | integer/string[5] | Int64 |
sfixed32 | Always four bytes. | int32 | int | int | int32 | Fixnum or Bignum (as required) | int | integer | int |
sfixed64 | Always eight bytes. | int64 | long | int/long[3] | int64 | Bignum | long | integer/string[5] | Int64 |
bool | bool | boolean | bool | bool | TrueClass/FalseClass | bool | boolean | bool | |
string | A string must always contain UTF-8 encoded or 7-bit ASCII text, and cannot be longer than 2^32. | string | String | str/unicode[4] | string | String (UTF-8) | string | string | String |
bytes | May contain any arbitrary sequence of bytes no longer than 2^32. | string | ByteString | str | []byte | String | String (ASCII-8BIT) | ByteString | string |
- 调用
set
方法的时候都会进行类型检查。
类型默认值
- 如果一个字段的值为默认值,那么序列化的时候,默认值不会被序列化。
singular
字段不能区域是否字段被设置,原因见1。- 参考字段默认值:
strings
: 空字符串。
bytes
: 空字节。
bools
:false
numberic
: 0。
enums
: 第一个定义的枚举值,必须是 0。
repeated
字段为空列表。
枚举类型
- 基本格式
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. } }
- 允许同一个值的字段名不同(别名), 使用
allow_alias
。 - 每个枚举类型的第一个值必须是0 (为了兼容
proto2
)。 - 枚举常量的范围必须在 32 位整数能够表示的范围之内。
-
保留值
enum Foo { reserved 2, 15, 9 to 11, 40 to max; reserved "FOO", "BAR"; }
- 字段名和数字的保留值不能写在同一行。
- 文章推荐
使用其他的 message
- 简单示例
message SearchResponse { repeated Result results = 1; } message Result { string url = 1; string title = 2; repeated string snippets = 3; }
- 导入其他
proto
的message
,使用import
关键字。import "myproject/other_protos.proto";
- 使用
-I
或--proto_path
指定搜索目录,默认在编译的目录搜索。 - 可以在
proto3
导入proto2
的message
,不建议混用。
嵌套调用
-
简单示例
// 内部类嵌套 message SearchResponse { message Result { string url = 1; string title = 2; repeated string snippets = 3; } repeated Result results = 1; } // 嵌套外部类 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; } } }
协议更新的规则
- 不要改变现有字段的数值。
- 老的代码会忽略新代码新增的字段,不影响旧代码解析新数据。
- 可以移除或者重命名字段名,建议增加
reserved
保留使用过的字段名或者值。 int32
、uint32
、int64
、uint64
和bool
之间可以相互转换。sint32
和sint64
彼此兼容,但是不和其他的整数类型兼容。- 只要都是
UTF-8
编码,string
和bytes
是相互兼容的。 fixed32
和sfixed32
兼容,fixed64
和sfixed64
兼容。- 将一个
singlular
字段移到一个新的oneof
是安全的。将任何一个singular
移到一个旧的oneof
是不安全的。
Any
-
Any
的使用import "google/protobuf/any.proto"; message ErrorStatus { string message = 1; repeated google.protobuf.Any details = 2; }
- 使用
Any
需要导入import google/protobuf/any.proto
。 - 二进制格式存储,可以包含任意的序列化的消息。
type.googleapis.com/_packagename_._messagename_.
解析消息类型的用途。
- 使用
-
import google/protobuf/any.proto
的实现syntax = "proto3"; package google.protobuf; ... message Any { string type_url = 1; bytes value = 2; }
oneof
-
示例用法
message SampleMessage { oneof test_oneof { string name = 4; SubMessage sub_message = 9; } }
map
和repeated
不能放在oneof
里面。oneof
设置了默认值之后,序列化的时候,默认值也包括在序列化数据中。- 移动一个
singular
字段到一个新的oneof
, 不会有问题。 - 从一个现有的
oneof
移入或者移除字段可能丢失一些信息。 - 从一个
oneof
中删除一个字段,然后再加回来,可能导致已序列化的数据丢失。
- 操作导致的
crash
SampleMessage message; SubMessage* sub_message = message.mutable_sub_message(); message.set_name("name"); // Will delete sub_message sub_message->set_... // Crashes here
- 由于设置了
set_name
了,sub_message
被删除,此时操作引起了crash
。
map
-
简单声明
map<key_type, value_type> map_field = N;
key
不是是enum
类型。value
不能是map
类型,其他都可以。- 不能加
repeated
字段修饰。 - 两个
map
进行merge
的时候,如果key
值重复,操作会失败。
-
map
的等价定义message MapFieldEntry { key_type key = 1; value_type value = 2; } repeated MapFieldEntry map_field = N;
Packages
-
作用: 避免命名冲突。
-
使用
package foo.bar; message Open { ... } // 其他的 proto message Foo { ... foo.bar.Open open = 1; ... }
c++
:等价于foo::bar
。java
: 如果没有指定java_package
,那么等价于指定包路径。python
: 没有作用。go
::如果没有指定go_package
,那么等价于指定包路径。c#
:如果没有指定csharp_namespace
, 那么等价于Foo.Bar
。
定义 Services
-
简单定义
service SearchService { rpc Search(SearchRequest) returns (SearchResponse); }
转 Json
proto3 | JSON | JSON example | Notes |
---|---|---|---|
message | object | {"fooBar": v, "g": null, …} | Generates JSON objects. Message field names are mapped to lowerCamelCase and become JSON object keys. If the json_name field option is specified, the specified value will be used as the key instead. Parsers accept both the lowerCamelCase name (or the one specified by the json_name option) and the original proto field name. null is an accepted value for all field types and treated as the default value of the corresponding field type. |
enum | string | "FOO_BAR" | The name of the enum value as specified in proto is used. Parsers accept both enum names and integer values. |
map<K,V> | object | {"k": v, …} | All keys are converted to strings. |
repeated V | array | [v, …] | null is accepted as the empty list [] . |
bool | true, false | true, false | |
string | string | "Hello World!" | |
bytes | base64 string | "YWJjMTIzIT8kKiYoKSctPUB+" | JSON value will be the data encoded as a string using standard base64 encoding with paddings. Either standard or URL-safe base64 encoding with/without paddings are accepted. |
int32, fixed32, uint32 | number | 1, -10, 0 | JSON value will be a decimal number. Either numbers or strings are accepted. |
int64, fixed64, uint64 | string | "1", "-10" | JSON value will be a decimal string. Either numbers or strings are accepted. |
float, double | number | 1.1, -10.0, 0, "NaN", "Infinity" | JSON value will be a number or one of the special string values “NaN”, “Infinity”, and “-Infinity”. Either numbers or strings are accepted. Exponent notation is also accepted. -0 is considered equivalent to 0. |
Any | object | {"@type": "url", "f": v, … } | If the Any contains a value that has a special JSON mapping, it will be converted as follows: {"@type": xxx, "value": yyy} . Otherwise, the value will be converted into a JSON object, and the "@type" field will be inserted to indicate the actual data type. |
Timestamp | string | "1972-01-01T10:00:20.021Z" | Uses RFC 3339, where generated output will always be Z-normalized and uses 0, 3, 6 or 9 fractional digits. Offsets other than “Z” are also accepted. |
Duration | string | "1.000340012s", "1s" | Generated output always contains 0, 3, 6, or 9 fractional digits, depending on required precision, followed by the suffix “s”. Accepted are any fractional digits (also none) as long as they fit into nano-seconds precision and the suffix “s” is required. |
Struct | object | { … } | Any JSON object. See struct.proto . |
Wrapper types | various types | 2, "2", "foo", true, "true", null, 0, … | Wrappers use the same representation in JSON as the wrapped primitive type, except that null is allowed and preserved during data conversion and transfer. |
FieldMask | string | "f.fooBar,h" | See field_mask.proto . |
ListValue | array | [foo, bar, …] | |
Value | value | Any JSON value. Check google.protobuf.Value for details. | |
NullValue | null | JSON null | |
Empty | object | {} | An empty JSON object |
proto
输出 json
的的时候,proto3
可能会有下列的行为:
- 忽略值为默认值的字段。
- 忽略未知字段。
- 输出字段转为驼峰命名法。
- 忽略枚举。
- 输入的枚举值以字符串格式存储,比如: 1 => “1”。
Options
java相关
java_package
: 指定输出的java
包名。option java_package = "com.example.foo";
java_outer_classname
: 输出的.proto
的文件名。option java_outer_classname = "Ponycopter";
java_multiple_files
: 是否输出多个.java
文件。如果为true
,每个class/enum
自己一个文件。
编译优化
-
SPEED(default)
运行速度快。 -
CODE_SIZE
: 编译的代码体积小,但是速度略有下降。 -
LITE_RUNTIME
: 运行速度能和SPEED
一样, 体积也比较小,但是想反射和descroptors
功能不能用了。option optimize_for = CODE_SIZE;
描述字段
deprecated
: 表明字段被废弃,不应咋使用。int32 old_field = 6 [deprecated = true];
下载
链接:https://pan.baidu.com/s/10lCpvwbXFnWyzhAIXorTzg
提取码:vzdw
[1] Protocol Buffers