Language Guide (proto3) 中英对照

Language Guide (proto3)

This guide describes how to use the protocol buffer language to structure your protocol buffer data, including .proto file syntax and how to generate data access classes from your .proto files. It covers the proto3 version of the protocol buffers language: for information on the proto2 syntax, see the Proto2 Language Guide.本指南介绍了如何使用 protocol buffer language来构造 protocol buffer data(包括.proto文件语法)以及如何从.proto文件生成数据访问类。它涵盖了rotocol buffers language的proto3版本:有关proto2语法的信息,请参见Proto2 Language Guide

This is a reference guide – for a step by step example that uses many of the features described in this document, see the tutorial for your chosen language (currently proto2 only; more proto3 documentation is coming soon).这是参考指南–有关使用本文档中描述的许多功能的分步示例,请参阅所选择语言的教程(当前仅适用于proto2;更多proto3文档即将发布)。

Defining A Message Type

First let's look at a very simple example. Let's say you want to define a search request message format, where each search request has a query string, the particular page of results you are interested in, and a number of results per page. Here's the .proto file you use to define the message type.首先让我们看一个非常简单的例子。假设您要定义一个搜索请求消息格式,其中每个搜索请求都有一个查询字符串,您感兴趣的特定结果页面以及每页结果数量。这是用于定义消息类型的.proto文件。

syntax = "proto3";

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}
  • The first line of the file specifies that you're using proto3 syntax: if you don't do this the protocol buffer compiler will assume you are using proto2. This must be the first non-empty, non-comment line of the file.文件的第一行指定您使用的是proto3语法:如果不这样做,则protocol buffer编译器将假定您使用的是proto2。这必须是文件的第一行非空,非注释行。
  • The SearchRequest message definition specifies three fields (name/value pairs), one for each piece of data that you want to include in this type of message. Each field has a name and a type.SearchRequest消息定义指定三个字段(名称/值对),每个字段要包含在此类型的消息中,每个字段对应一个。每个字段都有一个名称和类型。

Specifying Field Types

In the above example, all the fields are scalar types: two integers (page_number and result_per_page) and a string (query). However, you can also specify composite types for your fields, including enumerations and other message types.在上面的示例中,所有字段均为scalar types(标量类型,下文列举了):两个整数(page_number和result_per_page)和一个字符串(query)。但是,您也可以为字段指定复合类型,包括枚举和其他消息类型。

Assigning Field Numbers

As you can see, each field in the message definition has a unique number. These field numbers are used to identify your fields in the message binary format, and should not be changed once your message type is in use. Note that field numbers in the range 1 through 15 take one byte to encode, including the field number and the field's type (you can find out more about this in Protocol Buffer Encoding). Field numbers in the range 16 through 2047 take two bytes. So you should reserve the numbers 1 through 15 for very frequently occurring message elements. Remember to leave some room for frequently occurring elements that might be added in the future.如您所见,消息定义中的每个字段都有一个唯一的编号。这些字段号用于标识消息二进制格式的字段,一旦使用了消息类型,就不应更改这些字段号。请注意,范围为1到15的字段编号需要一个字节来编码,包括字段编号和字段的类型(您可以在Protocol Buffer Encoding中找到有关此内容的更多信息)。 16到2047之间的字段编号占用两个字节。因此,您应该为经常出现的消息元素保留数字1到15。切记为将来可能添加的频繁出现的元素留出一些空间。

The smallest field number you can specify is 1, and the largest is 2^29 - 1, or 536,870,911. You also cannot use the numbers 19000 through 19999 (FieldDescriptor::kFirstReservedNumber through FieldDescriptor::kLastReservedNumber), as they are reserved for the Protocol Buffers implementation - the protocol buffer compiler will complain if you use one of these reserved numbers in your .proto. Similarly, you cannot use any previously reserved field numbers.您可以指定的最小字段号是1,最大字段号是2^29 - 1或536,870,911。您也不能使用数字19000到19999(FieldDescriptor :: kFirstReservedNumber到FieldDescriptor :: kLastReservedNumber),因为它们是为Protocol Buffers实现保留的-如果在.proto中使用这些保留数之一,Protocol Buffers编译器会抱怨。同样,您不能使用任何以前保留的字段号。

Specifying Field Rules

Message fields can be one of the following:消息字段可以是以下之一:

  • singular: a well-formed message can have zero or one of this field (but not more than one). And this is the default field rule for proto3 syntax.单数:格式正确的message可以包含零个或一个此字段(但不能超过一个)。这是proto3语法的默认字段规则。
  • repeated: this field can be repeated any number of times (including zero) in a well-formed message. The order of the repeated values will be preserved.repeated:此字段可以在格式正确的消息中重复任意次(包括零次)。重复值的顺序将保留。

In proto3, repeated fields of scalar numeric types use packed encoding by default.在proto3中,标量数字类型的重复字段默认情况下使用压缩编码。

You can find out more about packed encoding in Protocol Buffer Encoding.

Adding More Message Types更多消息类型

Multiple message types can be defined in a single .proto file. This is useful if you are defining multiple related messages – so, for example, if you wanted to define the reply message format that corresponds to your SearchResponse message type, you could add it to the same .proto:可以在单个.proto文件中定义多种消息类型。如果要定义多个相关消息,这将非常有用–例如,如果要定义与SearchResponse消息类型相对应的答复消息格式,可以将其添加到相同的.proto中:

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

message SearchResponse {
 ...
}

Adding Comments添加注释

To add comments to your .proto files, use C/C++-style // and /* ... */ syntax.

/* 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.
}

Reserved Fields保留字段

If you update a message type by entirely removing a field, or commenting it out, future users can reuse the field number when making their own updates to the type. This can cause severe issues if they later load old versions of the same .proto, including data corruption, privacy bugs, and so on. One way to make sure this doesn't happen is to specify that the field numbers (and/or names, which can also cause issues for JSON serialization) of your deleted fields are reserved. The protocol buffer compiler will complain if any future users try to use these field identifiers.如果您通过完全删除字段或将其注释掉来更新消息类型,则将来的用户可以在自己对类型进行更新时重用该字段号。如果他们以后加载同一.proto的旧版本,可能会导致严重的问题,包括数据损坏,隐私错误等。确保不会发生这种情况的一种方法是指定保留已删除字段的字段编号(和/或名称,这也可能导致JSON序列化问题)。如果将来有用户尝试使用这些字段标识符,则协议缓冲区编译器会警告。

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

Note that you can't mix field names and field numbers in the same reserved statement.请注意,您不能在同一保留语句中混用字段名称和字段编号。

What's Generated From Your .proto?.proto产生了什么

When you run the protocol buffer compiler on a .proto, the compiler generates the code in your chosen language you'll need to work with the message types you've described in the file, including getting and setting field values, serializing your messages to an output stream, and parsing your messages from an input stream.在.proto上运行protocol buffer compiler时,编译器会以您选择的语言生成代码,您将需要使用该文件处理文件中描述的消息类型,包括获取和设置字段值,将消息序列化为输出流,并从输入流中解析消息。

  • For C++, the compiler generates a .h and .cc file from each .proto, with a class for each message type described in your file.
  • For Java, the compiler generates a .java file with a class for each message type, as well as a special Builder classes for creating message class instances.
  • Python is a little different – the Python compiler generates a module with a static descriptor of each message type in your .proto, which is then used with a metaclass to create the necessary Python data access class at runtime.
  • For Go, the compiler generates a .pb.go file with a type for each message type in your file.
  • For Ruby, the compiler generates a .rb file with a Ruby module containing your message types.
  • For Objective-C, the compiler generates a pbobjc.h and pbobjc.m file from each .proto, with a class for each message type described in your file.
  • For C#, the compiler generates a .cs file from each .proto, with a class for each message type described in your file.
  • For Dart, the compiler generates a .pb.dart file with a class for each message type in your file.

You can find out more about using the APIs for each language by following the tutorial for your chosen language (proto3 versions coming soon). For even more API details, see the relevant API reference (proto3 versions also coming soon).您可以按照所选语言的教程(即将推出proto3版本)找到有关每种语言使用API​​的更多信息。有关API的更多详细信息,请参见相关的API reference (proto3版本也即将推出)。

Scalar Value Types标量值类型

A scalar message field can have one of the following types – the table shows the type specified inthe .proto file, and the corresponding type in the automatically generated class:标量消息字段可以具有以下类型之一-该表显示.proto文件中指定的类型,以及自动生成的类中的相应类型:

.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 2^28.

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 2^56.

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 232.

string

String

str/unicode[4]

string

String (UTF-8)

string

string

String

        

bytes

May contain any arbitrary sequence of bytes no longer than 232.

string

ByteString

str

[]byte

String (ASCII-8BIT)

ByteString

string

List

        

You can find out more about how these types are encoded when you serialize your message in Protocol Buffer Encoding.在Protocol Buffer Encoding.中序列化消息时,您可以找到更多有关这些类型如何编码的信息。

Default Values默认值

When a message is parsed, if the encoded message does not contain a particular singular element, the corresponding field in the parsed object is set to the default value for that field. These defaults are type-specific:解析消息时,如果编码的消息不包含特定的单数元素,则已解析对象中的相应字段将设置为该字段的默认值。这些默认值是特定于类型的:

  • For strings, the default value is the empty string.
  • For bytes, the default value is empty bytes.
  • For bools, the default value is false.
  • For numeric types, the default value is zero.
  • For enums, the default value is the first defined enum value, which must be 0.
  • For message fields, the field is not set. Its exact value is language-dependent. See the generated code guide for details.

The default value for repeated fields is empty (generally an empty list in the appropriate language).

Note that for scalar message fields, once a message is parsed there's no way of telling whether a field was explicitly set to the default value (for example whether a boolean was set to false) or just not set at all: you should bear this in mind when defining your message types. For example, don't have a boolean that switches on some behaviour when set to false if you don't want that behaviour to also happen by default. Also note that if a scalar message field is set to its default, the value will not be serialized on the wire.请注意,对于标量消息字段,一旦解析了一条消息,就无法判断是将字段明确设置为默认值(例如,是否将布尔值设置为false)还是根本没有设置:您应该在定义消息类型时要注意。例如,如果您不希望默认情况下也发生这种情况,则当布尔值设置为false时,没有布尔值会打开某些行为。还要注意,如果将标量消息字段设置为其默认值,则该值将不会被序列化。

See the generated code guide for your chosen language for more details about how defaults work in generated code.有关默认值在生成的代码中如何工作的更多详细信息,请参见所选语言的生成的代码指南。

Enumerations枚举

When you're defining a message type, you might want one of its fields to only have one of apre-defined list of values. For example, let's say you want to add acorpus field for each SearchRequest, where the corpus can beUNIVERSAL, WEB, IMAGES, LOCAL, NEWS, PRODUCTS or VIDEO. You can do this very simply by adding an enum to your message definition with a constant for each possible value.定义消息类型时,您可能希望其字段之一仅具有一个预定义的值列表之一。例如,假设您要为每个SearchRequest添加一个corpus字段,该corpus可以是UNIVERSAL,WEB,IMAGES,LOCAL,NEWS,PRODUCTS或VIDEO。您可以通过在消息定义中添加一个枚举以及每个可能值的常量来非常简单地完成此操作。

In the following example we've added an enum called Corpus with all the possible values, and a field of type Corpus:在下面的示例中,我们添加了一个名为Corpus的枚举,其中包含所有可能的值以及一个Corpus类型的字段:

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;
}

As you can see, the Corpus enum's first constant maps to zero: every enum definition must contain a constant that maps to zero as its first element. This is because:如您所见,Corpus枚举的第一个常量映射为零:每个枚举定义必须包含一个映射为零的常量作为其第一个元素。这是因为:

  • There must be a zero value, so that we can use 0 as a numeric default value.必须有一个零值,以便我们可以使用0作为数字默认值。
  • The zero value needs to be the first element, for compatibility with the proto2 semantics where the first enum value is always the default.零值必须是第一个元素,以便与proto2语义兼容,其中第一个枚举值始终是默认值。

You can define aliases by assigning the same value to different enum constants. To do this you need to set the allow_alias option to true, otherwise the protocol compiler will generate an error message when aliases are found.您可以通过将相同的值分配给不同的枚举常量来定义别名。为此,您需要将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.
  }
}

Enumerator constants must be in the range of a 32-bit integer. Since enum values use varint encoding on the wire, negative values are inefficient and thus not recommended. You can define enums within a message definition, as in the above example, or outside – these enums can be reused in any message definition in your .proto file. You can also use an enum type declared in one message as the type of a field in a different message, using the syntax MessageType.EnumType.枚举器常量必须在32位整数范围内。由于枚举值使用varint编码,因此负值效率不高,因此不建议使用。您可以在消息定义内定义枚举,如上例所示,也可以在外部定义-这些枚举可以在.proto文件中的任何消息定义中重复使用。您还可以使用语法MessageType.EnumType将一条消息中声明的枚举类型用作另一条消息中字段的类型。

When you run the protocol buffer compiler on a .proto that uses an enum, the generated code will have a corresponding enum for Java or C++, a special EnumDescriptor class for Python that's used to create a set of symbolic constants with integer values in the runtime-generated class.在使用枚举的.proto上运行 protocol buffer编译器时,生成的代码将具有一个对应于Java或C ++的枚举,一个特殊的Python EnumDescriptor类,用于在运行时创建带有整数值的符号常量集生成的类。

Caution: the generated code may be subject to language-specific limitations on the number of enumerators (low thousands for one language). Please review the limitations for the languages you plan to use.注意:生成的代码可能受到语言特定的枚举数限制。请查看您计划使用的语言的限制。

During deserialization, unrecognized enum values will be preserved in the message, though how this is represented when the message is deserialized is language-dependent. In languages that support open enum types with values outside the range of specified symbols, such as C++ and Go, the unknown enum value is simply stored as its underlying integer representation. In languages with closed enum types such as Java, a case in the enum is used to represent an unrecognized value, and the underlying integer can be accessed with special accessors. In either case, if the message is serialized the unrecognized value will still be serialized with the message.在反序列化期间,无法识别的枚举值将保留在消息中,因此在反序列化消息时如何表示该值取决于语言。在支持具有超出指定符号范围的值的开放式枚举类型的语言(例如C ++和Go)中,未知的枚举值仅存储为其基础整数表示形式。在具有封闭枚举类型的语言(例如Java)中,枚举中的大小写用于表示无法识别的值,并且可以使用特殊的访问器访问基础整数。无论哪种情况,如果消息被序列化,则无法识别的值仍将与消息一起序列化。

For more information about how to work with message enums in your applications, see the generated code guide for your chosen language.有关如何在应用程序中使用消息枚举的更多信息,请参见针对所选语言生成的代码指南。

Reserved Values保留值

If you update an enum type by entirely removing an enum entry, or commenting it out, future users can reuse the numeric value when making their own updates to the type. This can cause severe issues if they later load old versions of the same .proto, including data corruption, privacy bugs, and so on. One way to make sure this doesn't happen is to specify that the numeric values (and/or names, which can also cause issues for JSON serialization) of your deleted entries are reserved. The protocol buffer compiler will complain if any future users try to use these identifiers. You can specify that your reserved numeric value range goes up to the maximum possible value using the max keyword.如果通过完全删除枚举条目或将其注释掉来更新枚举类型,则将来的用户在自己对类型进行更新时可以重用数值。如果他们以后加载同一.proto的旧版本,可能会导致严重的问题,包括数据损坏,隐私错误等。确保不会发生这种情况的一种方法是指定保留已删除条目的数字值(和/或名称,这也可能导致JSON序列化问题)。如果将来有任何用户尝试使用这些标识符,则协议缓冲区编译器会抱怨。您可以使用max关键字指定保留的数值范围达到最大可能值。

enum Foo {
  reserved 2, 15, 9 to 11, 40 to max;
  reserved "FOO", "BAR";
}

Note that you can't mix field names and numeric values in the same reserved statement.请注意,您不能在同一保留语句中混合使用字段名和数字值。

Using Other Message Types使用其他消息类型

You can use other message types as field types. For example, let's say you wanted to include Result messages in each SearchResponse message – to do this, you can define a Result message type in the same .proto and then specify a field of type Result in SearchResponse:您可以使用其他消息类型作为字段类型。例如,假设您要在每条SearchResponse消息中包括Result 消息–为此,您可以在同一.proto中定义Result 消息类型,然后在SearchResponse中指定Result 类型的字段:

message SearchResponse {
  repeated Result results = 1;
}

message Result {
  string url = 1;
  string title = 2;
  repeated string snippets = 3;
}

Importing Definitions导入定义

In the above example, the Result message type is defined in the same file as SearchResponse – what if the message type you want to use as a field type is already defined in another .proto file?在上面的示例中,“Result ”消息类型与SearchResponse定义在同一文件中-如果要在另一个.proto文件中定义要用作字段类型的消息类型,该怎么办?

You can use definitions from other .proto files by importing them. To import another .proto's definitions, you add an import statement to the top of your file:您可以通过导入其他.proto文件使用它们的定义。要导入另一个.proto的定义,请在文件顶部添加一个import语句:

import "myproject/other_protos.proto";

By default you can only use definitions from directly imported .proto files. However, sometimes you may need to move a .proto file to a new location. Instead of moving the .proto file directly and updating all the call sites in a single change, now you can put a dummy .proto file in the old location to forward all the imports to the new location using the import public notion. import public dependencies can be transitively relied upon by anyone importing the proto containing the import public statement. For example:默认情况下,您只能使用直接导入的.proto文件中的定义。但是,有时您可能需要将.proto文件移动到新位置。现在,您可以直接在原始位置放置一个虚拟.proto文件,而不是直接移动.proto文件并一次更改所有呼叫站点,而是使用import public概念将所有导入转发到新位置。任何导入包含import public 的原型的人都可以可传递地依赖import public 项。例如:

// new.proto
// All definitions are moved here
// old.proto
// This is the proto that all clients are importing.
import public "new.proto";
import "other.proto";
// client.proto
import "old.proto";
// You use definitions from old.proto and new.proto, but not other.proto

The protocol compiler searches for imported files in a set of directories specified on the protocol compiler command line using the -I/--proto_path flag. If no flag was given, it looksin the directory in which the compiler was invoked. In general you should setthe --proto_path flag to the root of your project and use fully qualified names for all imports.协议编译器使用-I/--proto_path 标志在协议编译器命令行中指定的一组目录中搜索导入的文件。如果未给出标志,它将在调用编译器的目录中查找。通常,应将--proto_path标志设置为项目的根目录,并对所有导入使用完全限定的名称

Using proto2 Message Types

It's possible to import proto2 message types and use them in your proto3 messages, and vice versa. However, proto2 enums cannot be used directly in proto3 syntax (it's okay if an imported proto2 message uses them).可以导入proto2消息类型并在proto3消息中使用它们,反之亦然。但是,不能在proto3语法中直接使用proto2枚举(如果导入的proto2消息使用它们,也可以)。

Nested Types

You can define and use message types inside other message types, as in the following example – here the Result message is defined inside the SearchResponse message:您可以在其他消息类型中定义和使用消息类型,如以下示例所示–在SearchResponse消息中定义了Result消息:

message SearchResponse {
  message Result {
    string url = 1;
    string title = 2;
    repeated string snippets = 3;
  }
  repeated Result results = 1;
}

If you want to reuse this message type outside its parent message type, you refer to it as Parent.Type:如果要在父消息类型之外重用此消息类型,则将其称为Parent.Type:

message SomeOtherMessage {
  SearchResponse.Result result = 1;
}

You can nest messages as deeply as you like:您可以根据需要嵌套消息:

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;
    }
  }
}

Updating A Message Type更新消息类型

If an existing message type no longer meets all your needs – for example, you'd like the message format to have an extra field – but you'd still like to use code created with the old format, don't worry! It's very simple to update message types without breaking any of your existing code. Just remember the following rules:如果现有的消息类型不再满足您的所有需求(例如,您希望消息格式具有一个额外的字段),但是您仍然希望使用以旧格式创建的代码,请不要担心!在不破坏任何现有代码的情况下更新消息类型非常简单。只要记住以下规则:

  • Don't change the field numbers for any existing fields.不要更改任何现有字段的字段编号。
  • If you add new fields, any messages serialized by code using your "old" message format can still be parsed by your new generated code. You should keep in mind the default values for these elements so that new code can properly interact with messages generated by old code. Similarly, messages created by your new code can be parsed by your old code: old binaries simply ignore the new field when parsing. See the Unknown Fields section for details.如果添加新字段,则仍可以使用新生成的代码来解析使用“旧”消息格式通过代码序列化的任何消息。您应记住这些元素的默认值,以便新代码可以与旧代码生成的消息正确交互。同样,由新代码创建的消息也可以由旧代码解析:旧的二进制文件在解析时只会忽略新字段。有关详细信息,请参见Unknown Fields部分。
  • Fields can be removed, as long as the field number is not used again in your updated message type. You may want to rename the field instead, perhaps adding the prefix "OBSOLETE_", or make the field number reserved, so that future users of your .proto can't accidentally reuse the number.只要在更新的消息类型中不再使用字段号,就可以删除字段。您可能想要重命名该字段,或者添加前缀“ OBSOLETE_”,或者保留该字段编号,以使.proto的将来用户不会意外重用该编号。
  • int32, uint32, int64, uint64, and bool are all compatible – this means you can change a field from one of these types to another without breaking forwards- or backwards-compatibility. If a number is parsed from the wire which doesn't fit in the corresponding type, you will get the same effect as if you had cast the number to that type in C++ (e.g. if a 64-bit number is read as an int32, it will be truncated to 32 bits).int32,uint32,int64,uint64和bool都是兼容的–这意味着您可以将字段从这些类型中的一种更改为另一种,而不会破坏向前或向后的兼容性。如果从对应的类型不匹配解析出的一个数字,则将获得与在C ++中将该数字强制转换为该类型一样的效果(例如,如果将64位数字读取为int32,它将被截断为32位)。
  • sint32 and sint64 are compatible with each other but are not compatible with the other integer types.sint32 and sint64彼此兼容,但与其他整数类型不兼容
  • string and bytes are compatible as long as the bytes are valid UTF-8.string and bytes 兼容,只要字节是有效的UTF-8。
  • Embedded messages are compatible with bytes if the bytes contain an encoded version of the message.如果bytes包含消息的编码版本,则嵌套的消息与bytes兼容。
  • fixed32 is compatible with sfixed32, and fixed64 with sfixed64.
  • For string, bytes, and message fields, optional is compatible with repeated. Given serialized data of a repeated field as input, clients that expect this field to be optional will take the last input value if it's a primitive type field or merge all input elements if it's a message type field. Note that this is not generally safe for numeric types, including bools and enums. Repeated fields of numeric types can be serialized in the packed format, which will not be parsed correctly when an optional field is expected.对于 string, bytes和message 字段,optional 与repeated兼容。给定重复字段的序列化数据作为输入,如果期望该字段是可选的,则如果它是原始类型字段,则将采用最后一个输入值;如果是消息类型字段,则将合并所有输入元素。请注意,这对于数字类型(包括布尔值和枚举)通常并不安全。重复的数字类型字段可以以打包格式序列化,当期望使用可选字段时,将无法正确解析该格式。
  • enum is compatible with int32, uint32, int64, and uint64 in terms of wire format (note that values will be truncated if they don't fit). However be aware that client code may treat them differently when the message is deserialized: for example, unrecognized proto3 enum types will be preserved in the message, but how this is represented when the message is deserialized is language-dependent. Int fields always just preserve their value.enum在连线格式方面与int32,uint32,int64和uint64兼容(请注意,如果值不合适,该值将被截断)。但是,请注意,客户端代码在反序列化消息时可能会以不同的方式对待它们:例如,无法识别的proto3枚举类型将保留在消息中,但是反序列化消息时如何表示这取决于语言。 Int字段始终只是保留其值。
  • Changing a single value into a member of a newoneof is safe and binary compatible. Moving multiple fields into a new oneof may be safe if you are sure that no code sets more than one at a time. Moving any fields into an existing oneof is not safe.将单个值更改为新的oneof的成员是安全且二进制兼容的。如果您确定一次没有代码设置多个字段,那么将多个字段移动到一个新字段中可能是安全的。将任何字段移至现有字段都不安全。

Unknown Fields未知字段

Unknown fields are well-formed protocol buffer serialized data representing fields that the parser does not recognize. For example, when an old binary parses data sent by a new binary with new fields, those new fields become unknown fields in the old binary.未知字段是格式正确的protocol buffer序列化数据,表示解析器无法识别的字段。例如,当旧二进制文件使用新字段解析新二进制文件发送的数据时,这些新字段将成为旧二进制文件中的未知字段。

Originally, proto3 messages always discarded unknown fields during parsing, but in version 3.5 we reintroduced the preservation of unknown fields to match the proto2 behavior. In versions 3.5 and later, unknown fields are retained during parsing and included in the serialized output.最初,proto3消息在解析过程中总是丢弃未知字段,但是在版本3.5中,我们重新引入了保留未知字段以匹配proto2行为的功能。在版本3.5及更高版本中,未知字段将在解析期间保留并包含在序列化输出中。

Any Any消息类型

The Any message type lets you use messages as embedded types without having their .proto definition. An Any contains an arbitrary serialized message as bytes, along with a URL that acts as a globally unique identifier for and resolves to that message's type. To use the Any type, you need to importgoogle/protobuf/any.proto.Any消息类型使您可以将消息用作嵌入类型,而无需定义它们的.proto。 Any包含任意序列化的消息(以字节为单位)以及URL,URL作为该消息的类型并解析为该消息的类型的全局唯一标识符。要使用Any类型,您需要导入google / protobuf / any.proto。

import "google/protobuf/any.proto";

message ErrorStatus {
  string message = 1;
  repeated google.protobuf.Any details = 2;
}

The default type URL for a given message type is type.googleapis.com/packagename.messagename.

Different language implementations will support runtime library helpers to pack and unpack Any values in a typesafe manner – for example, in Java, the Any type will have special pack() and unpack() accessors, while in C++ there are PackFrom() and UnpackTo() methods:不同的语言实现将支持运行时库帮助程序以类型安全的方式打包和解压缩Any值-例如,在Java中,Any类型将具有特殊的pack()和unpack()访问器,而在C ++中则具有PackFrom()和UnpackTo () 方法:

// Storing an arbitrary message type in Any.
NetworkErrorDetails details = ...;
ErrorStatus status;
status.add_details()->PackFrom(details);

// Reading an arbitrary message from Any.
ErrorStatus status = ...;
for (const Any& detail : status.details()) {
  if (detail.Is<NetworkErrorDetails>()) {
    NetworkErrorDetails network_error;
    detail.UnpackTo(&network_error);
    ... processing network_error ...
  }
}

Currently the runtime libraries for working with Any types are under development.当前,正在开发用于任何类型的运行时库。

If you are already familiar with proto2 syntax, the Any type replaces extensions.如果您已经熟悉proto2语法,则Any类型将替换扩展名。

Oneof

If you have a message with many fields and where at most one field will be set at the same time, you can enforce this behavior and save memory by using the oneof feature.如果您有一则消息包含多个字段,并且最多可以同时设置一个字段,则可以使用oneof功能强制执行此行为并节省内存。

Oneof fields are like regular fields except all the fields in a oneof share memory, and at most one field can be set at the same time. Setting any member of the oneof automatically clears all the other members. You can check which value in a oneof is set (if any) using a special case() or WhichOneof() method, depending on your chosen language.Oneof字段与常规字段类似,不同之处在于Oneof共享内存中的所有字段,并且最多可以同时设置一个字段。设置oneof中的任何成员会自动清除所有其他成员。您可以根据所选择的语言,使用特殊case()或whichOneof()方法来检查oneof中的哪个值(如果有)。

Using Oneof

To define a oneof in your .proto you use the oneof keyword followed by your oneof name, in this case test_oneof:要在.proto中定义一个oneof,请使用oneof关键字,后跟您的oneof名称,在本例中为test_oneof

message SampleMessage {
  oneof test_oneof {
    string name = 4;
    SubMessage sub_message = 9;
  }
}

You then add your oneof fields to the oneof definition. You can add fields of any type, except map fields and repeated fields.然后,将oneof字段添加到oneof定义。您可以添加任何类型的字段,但map字段和repeated 字段除外。

In your generated code, oneof fields have the same getters and setters as regular fields. You also get a special method for checking which value (if any) in the oneof is set. You can find out more about the oneof API for your chosen language in the relevant API reference.在您生成的代码中,oneof 字段具有与常规字段相同的getter和setter。您还将获得一种特殊的方法来检查oneof中的哪个值(如果有)。您可以在相关的API参考中找到有关所选语言的oneof API的更多信息。

Oneof Features

  • Setting a oneof field will automatically clear all other members of the oneof. So if you set several oneof fields, only the last field you set will still have a value.设置oneof字段将自动清除oneof的所有其他成员。因此,如果您设置几个字段中的一个,则仅您设置的最后一个字段仍将具有值。
SampleMessage message;
message.set_name("name");
CHECK(message.has_name());
message.mutable_sub_message();   // Will clear name field.
CHECK(!message.has_name());
  • If the parser encounters multiple members of the same oneof on the wire, only the last member seen is used in the parsed message.如果解析器在线路上遇到同一个对象的多个成员,则在解析的消息中仅使用最后看到的成员.
  • A oneof cannot be repeated.
  • Reflection APIs work for oneof fields.反射API适用于其中一个字段。
  • If you set a oneof field to the default value (such as setting an int32 oneof field to 0), the "case" of that oneof field will be set, and the value will be serialized on the wire.如果将oneof字段设置为默认值(例如将int32 oneof字段设置为0),则将设置该oneof字段的“大小写”,并且该值将在线路上序列化。
  • If you're using C++, make sure your code doesn't cause memory crashes. The following sample code will crash because sub_message was already deleted by calling the set_name() method.如果您使用的是C ++,请确保您的代码不会导致内存崩溃。以下示例代码将崩溃,因为通过调用set_name()方法已经删除了sub_message。
SampleMessage message;
SubMessage* sub_message = message.mutable_sub_message();
message.set_name("name");      // Will delete sub_message
sub_message->set_...            // Crashes here
  • Again in C++, if you Swap() two messages with oneofs, each message will end up with the other’s oneof case: in the example below, msg1 will have a sub_message and msg2 will have a name.同样,在C ++中,如果您将两个oneofs 消息用Swap()交换,则每个消息将以另一个的oneof结尾:在下面的示例中,msg1将具有sub_message,而msg2将具有name。
SampleMessage msg1;
msg1.set_name("name");
SampleMessage msg2;
msg2.mutable_sub_message();
msg1.swap(&msg2);
CHECK(msg1.has_sub_message());
CHECK(msg2.has_name());

Backwards-compatibility issues向后兼容问题

Be careful when adding or removing oneof fields. If checking the value of a oneof returns None/NOT_SET, it could mean that the oneof has not been set or it has been set to a field in a different version of the oneof. There is no way to tell the difference, since there's no way to know if an unknown field on the wire is a member of the oneof.添加或删除字段之一时请多加注意。如果检查oneof的值返回None / NOT_SET,则可能意味着oneof尚未设置或已被设置为oneof的不同版本中的字段。由于无法知道未知字段是否是oneof的成员,因此无法分辨出差异。

Tag Reuse Issues标签重用问题

  • Move fields into or out of a oneof: You may lose some of your information (some fields will be cleared) after the message is serialized and parsed. However, you can safely move a single field into a new oneof and may be able to move multiple fields if it is known that only one is ever set.将字段移入或移出oneof:在对消息进行序列化和解析后,您可能会丢失一些信息(某些字段将被清除)。但是,您可以安全地将单个字段移动到新字段中,并且如果知道只设置了一个字段,则可以移动多个字段。
  • Delete a oneof field and add it back: This may clear your currently set oneof field after the message is serialized and parsed.删除一个oneof字段并将其重新添加:在对消息进行序列化和解析之后,这可能会清除您当前设置的oneof字段。
  • Split or merge oneof: This has similar issues to moving regular fields.拆分或合并其中之一:与移动常规字段有类似的问题。

Maps

If you want to create an associative map as part of your data definition, protocol buffers provides a handy shortcut syntax:如果要在数据定义中创建map,protocol buffers提供了一种方便的快捷方式语法:

map<key_type, value_type> map_field = N;

...where the key_type can be any integral or string type (so, any scalar type except for floating point types and bytes). Note that enum is not a valid key_type. The value_type can be any type except another map....其中key_type可以是任何整数或字符串类型(因此,除了浮点类型和字节之外,任何标量类型)。请注意,枚举不是有效的key_type。 value_type可以是除另一个映射以外的任何类型。

So, for example, if you wanted to create a map of projects where each Project message is associated with a string key, you could define it like this:因此,例如,如果您想创建一个项目地图,其中每个Project消息都与一个字符串键相关联,则可以这样定义它:

map<string, Project> projects = 3;
  • Map fields cannot be repeated.
  • Wire format ordering and map iteration ordering of map values is undefined, so you cannot rely on your map items being in a particular order.数据格式排序和map排序是不确定的,因此您不能依赖于map的特定顺序。
  • When generating text format for a .proto, maps are sorted by key. Numeric keys are sorted numerically.为.proto生成文本格式时,地图按键排序。数字键按数字排序。
  • When parsing from the wire or when merging, if there are duplicate map keys the last key seen is used. When parsing a map from text format, parsing may fail if there are duplicate keys.从数据解析或合并时,如果存在重复的映射键,则使用最后看到的键。从文本格式解析map时,如果键重复,则解析可能会失败。
  • If you provide a key but no value for a map field, the behavior when the field is serialized is language-dependent. In C++, Java, and Python the default value for the type is serialized, while in other languages nothing is serialized.如果为映射字段提供键但没有值,则序列化字段时的行为取决于语言。在C ++,Java和Python中,类型的默认值是序列化的,而在其他语言中,则没有序列化的值。

The generated map API is currently available for all proto3 supported languages. You can find out more about the map API for your chosen language in the relevant API reference.生成的地图API当前可用于所有proto3支持的语言。您可以在相关API reference中找到有关所选语言的map API的更多信息。

Backwards compatibility

The map syntax is equivalent to the following on the wire, so protocol buffers implementations that do not support maps can still handle your data:map语法与以下语法等效,因此不支持map的protocol buffers 实现仍可以处理您的数据:

message MapFieldEntry {
  key_type key = 1;
  value_type value = 2;
}

repeated MapFieldEntry map_field = N;

Any protocol buffers implementation that supports maps must both produce and accept data that can be accepted by the above definition.任何支持 maps的 protocol buffers 实现都必须产生并接受上述定义可以接受的数据。

Packages

You can add an optional package specifier to a .proto file to prevent name clashes between protocol message types.您可以将可选的package 说明符添加到.proto文件中,以防止协议消息类型之间的名称冲突。

package foo.bar;
message Open { ... }

You can then use the package specifier when defining fields of your message type:然后,可以在定义消息类型的字段时使用包说明符:

message Foo {
  ...
  foo.bar.Open open = 1;
  ...
}

The way a package specifier affects the generated code depends on your chosen language:包说明符影响生成的代码的方式取决于您选择的语言:

  • In C++ the generated classes are wrapped inside a C++ namespace. For example, Open would be in the namespace foo::bar.在C ++中,生成的类包装在C ++名称空间中。例如,Open将位于名称空间foo :: bar中。
  • In Java, the package is used as the Java package, unless you explicitly provide an option java_package in your .proto file.
  • In Python, the package directive is ignored, since Python modules are organized according to their location in the file system.
  • In Go, the package is used as the Go package name, unless you explicitly provide an option go_package in your .proto file.
  • In Ruby, the generated classes are wrapped inside nested Ruby namespaces, converted to the required Ruby capitalization style (first letter capitalized; if the first character is not a letter, PB_ is prepended). For example, Open would be in the namespace Foo::Bar.
  • In C# the package is used as the namespace after converting to PascalCase, unless you explicitly provide an option csharp_namespace in your .proto file. For example, Open would be in the namespace Foo.Bar.

Packages and Name Resolution软件包和名称解析

Type name resolution in the protocol buffer language works like C++: first the innermost scope is searched, then the next-innermost, and so on, with each package considered to be "inner" to its parent package. A leading '.' (for example, .foo.bar.Baz) means to start from the outermost scope instead.protocol buffer中的类型名称解析类似于C ++:首先搜索最内层的作用域,然后搜索下一个最内层的作用,依此类推,每个包都被视为其父包“内在”。领先的“.” (例如.foo.bar.Baz)表示从最外面的范围开始。

The protocol buffer compiler resolves all type names by parsing the imported .proto files. The code generator for each language knows how to refer to each type in that language, even if it has different scoping rules. protocol buffer译器通过解析导入的.proto文件来解析所有类型名称。每种语言的代码生成器都知道如何引用该语言中的每种类型,即使它具有不同的范围规则。

Defining Services定义服务

If you want to use your message types with an RPC (Remote Procedure Call) system, you can define an RPC service interface in a .proto file and the protocol buffer compiler will generate service interface code and stubs in your chosen language. So, for example, if you want to define an RPC service with a method that takes your SearchRequest and returns a SearchResponse, you can define it in your .proto file as follows:如果要将消息类型与RPC(远程过程调用)系统一起使用,则可以在.proto文件中定义RPC服务接口,并且protocol buffer 编译器将以您选择的语言生成服务接口代码和存根。因此,例如,如果要使用接收SearchRequest并返回SearchResponse的方法来定义RPC服务,则可以在.proto文件中对其进行定义,如下所示:

service SearchService {
  rpc Search (SearchRequest) returns (SearchResponse);
}

The most straightforward RPC system to use with protocol buffers is gRPC: a language- and platform-neutral open source RPC system developed at Google. gRPC works particularly well with protocol buffers and lets you generate the relevant RPC code directly from your .proto files using a special protocol buffer compiler plugin.与protocol buffers一起使用的最简单的RPC系统是 gRPC:这是Google开发的与语言和平台无关的开源RPC系统。 gRPC与协议缓冲区配合使用特别好,并允许您使用特殊的协议缓冲区编译器插件直接从.proto文件生成相关的RPC代码。

If you don't want to use gRPC, it's also possible to use protocol buffers with your own RPC implementation. You can find out more about this in the Proto2 Language Guide.如果您不想使用gRPC,也可以在自己的RPC实现中使用协议缓冲区。您可以在《 Proto2语言指南》中找到有关此内容的更多信息。

There are also a number of ongoing third-party projects to develop RPC implementations for Protocol Buffers. For a list of links to projects we know about, see the third-party add-ons wiki page.还有许多正在进行的第三方项目正在为协议缓冲区开发RPC实现。有关我们了解的项目的链接列表,请参见第三方加载项Wiki页面。

JSON Mapping

Proto3 supports a canonical encoding in JSON, making it easier to share data between systems. The encoding is described on a type-by-type basis in the table below.Proto3支持JSON中的规范编码,从而使在系统之间共享数据更加容易。下表中按类型对编码进行了描述。

If a value is missing in the JSON-encoded data or if its value is null, it will be interpreted as the appropriate default value when parsed into a protocol buffer.If a field has the default value in the protocol buffer, it will be omitted in the JSON-encoded data by default to save space.An implementation may provide options to emit fields with default values in the JSON-encoded output.如果JSON编码的数据中缺少某个值,或者该值为null,则在解析为协议缓冲区时,它将被解释为适当的默认值。如果字段在协议缓冲区中具有默认值,则默认情况下会在JSON编码数据中将其省略以节省空间。一个实现可以提供选项,以在JSON编码的输出中发出具有默认值的字段。

proto3JSONJSON exampleNotes
messageobject`{"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.
enumstring`"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 Varray`[v, …]``null` is accepted as the empty list [].
booltrue, false`true, false` 
stringstring`"Hello World!"` 
bytesbase64 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, uint32number`1, -10, 0`JSON value will be a decimal number. Either numbers or strings are accepted.
int64, fixed64, uint64string`"1", "-10"`JSON value will be a decimal string. Either numbers or strings are accepted.
float, doublenumber`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.
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.
Timestampstring`"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.
Durationstring`"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 typesvarious 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.
FieldMaskstring`"f.fooBar,h"`See `field_mask.proto`.
ListValuearray`[foo, bar, …]` 
Valuevalue Any JSON value
NullValuenull JSON null
Emptyobject{}An empty JSON object

JSON options

A proto3 JSON implementation may provide the following options:

  • Emit fields with default values: Fields with default values are omitted by default in proto3 JSON output. An implementation may provide an option to override this behavior and output fields with their default values.发出具有默认值的字段:默认情况下,proto3 JSON输出中省略具有默认值的字段。一个实现可以提供一个选项,以使用其默认值覆盖此行为和输出字段。
  • Ignore unknown fields: Proto3 JSON parser should reject unknown fields by default but may provide an option to ignore unknown fields in parsing.忽略未知字段:默认情况下,Proto3 JSON解析器应拒绝未知字段,但可以提供在解析时忽略未知字段的选项。
  • Use proto field name instead of lowerCamelCase name: By default proto3 JSON printer should convert the field name to lowerCamelCase and use that as the JSON name. An implementation may provide an option to use proto field name as the JSON name instead. Proto3 JSON parsers are required to accept both the converted lowerCamelCase name and the proto field name.使用proto字段名称代替lowerCamelCase名称:默认情况下,proto3 JSON打印机应将字段名称转换为lowerCamelCase并将其用作JSON名称。一个实现可以提供一个选项,改为使用原型字段名称作为JSON名称。 Proto3 JSON解析器必须接受转换后的lowerCamelCase名称和原型字段名称。
  • Emit enum values as integers instead of strings: The name of an enum value is used by default in JSON output. An option may be provided to use the numeric value of the enum value instead.将枚举值作为整数而不是字符串发送:枚举值的名称默认在JSON输出中使用。可以提供一个选项来代替使用枚举值的数字值。

Options

Individual declarations in a .proto file can be annotated with a number of options. Options do not change the overall meaning of a declaration, but may affect the way it is handled in a particular context. The complete list of available options is defined in google/protobuf/descriptor.proto..proto文件中的各个声明可以使用许多选项进行注释。选项不会改变声明的整体含义,但可能会影响在特定上下文中处理声明的方式。可用选项的完整列表在google/protobuf/descriptor.proto.中定义。

Some options are file-level options, meaning they should be written at the top-level scope, not inside any message, enum, or service definition. Some options are message-level options, meaning they should be written inside message definitions. Some options are field-level options, meaning they should be written inside field definitions. Options can also be written on enum types, enum values, oneof fields, service types, and service methods; however, no useful options currently exist for any of these.一些选项是文件级选项,这意味着它们应该在顶级范围内编写,而不是在任何消息,枚举或服务定义内。一些选项是消息级别的选项,这意味着它们应该写在消息定义中。一些选项是字段级选项,这意味着它们应在字段定义中编写。选项也可以写在枚举类型,枚举值,字段,服务类型和服务方法中;但是,目前对于这些功能都不存在有用的选项。

Here are a few of the most commonly used options:以下是一些最常用的选项:

  • java_package (file option): The package you want to use for your generated Java classes. If no explicit java_package option is given in the .proto file, then by default the proto package (specified using the "package" keyword in the .proto file) will be used. However, proto packages generally do not make good Java packages since proto packages are not expected to start with reverse domain names. If not generating Java code, this option has no effect.您要用于生成的Java类的包。如果.proto文件中未提供显式的java_package选项,则默认情况下将使用proto软件包(在.proto文件中使用“ package”关键字指定)。但是,proto软件包通常不能成为良好的Java软件包,因为proto软件包不应以反向域名开头。如果未生成Java代码,则此选项无效。
option java_package = "com.example.foo";
  • java_multiple_files (file option): Causes top-level messages, enums, and services to be defined at the package level, rather than inside an outer class named after the .proto file.使顶级消息,枚举和服务在包级别定义,而不是在以.proto文件命名的外部类内部定义。
option java_multiple_files = true;
  • java_outer_classname (file option): The class name for the outermost Java class (and hence the file name) you want to generate. If no explicit java_outer_classname is specified in the .proto file, the class name will be constructed by converting the .proto file name to camel-case (so foo_bar.proto becomes FooBar.java). If not generating Java code, this option has no effect.您要生成的最外层Java类的类名(以及文件名)。如果在.proto文件中未指定显式的java_outer_classname,则通过将.proto文件名转换为驼峰式大小写来构造类名(因此foo_bar.proto变为FooBar.java)。如果未生成Java代码,则此选项无效。
option java_outer_classname = "Ponycopter";
  • optimize_for (file option): Can be set to SPEED, CODE_SIZE, or LITE_RUNTIME. This affects the C++ and Java code generators (and possibly third-party generators) in the following ways:可以设置为SPEED,CODE_SIZE或LITE_RUNTIME。这会以下列方式影响C ++和Java代码生成器(可能还有第三方生成器):
    • SPEED (default): The protocol buffer compiler will generate code for serializing, parsing, and performing other common operations on your message types. This code is highly optimized.protocol buffer编译器将生成用于对消息类型进行序列化,解析和执行其他常见操作的代码。此代码已高度优化。
    • CODE_SIZE: The protocol buffer compiler will generate minimal classes and will rely on shared, reflection-based code to implement serialialization, parsing, and various other operations. The generated code will thus be much smaller than with SPEED, but operations will be slower. Classes will still implement exactly the same public API as they do in SPEED mode. This mode is most useful in apps that contain a very large number .proto files and do not need all of them to be blindingly fast.协议缓冲区编译器将生成最少的类,并将依赖于基于反射的共享代码来实现序列化,解析和其他各种操作。因此,生成的代码将比使用SPEED的代码小得多,但是操作会更慢。类仍将实现与在SPEED模式下完全相同的公共API。此模式在包含大量.proto文件且不需要所有文件快速提高速度的应用程序中最有用。
    • LITE_RUNTIME: The protocol buffer compiler will generate classes that depend only on the "lite" runtime library (libprotobuf-lite instead of libprotobuf). The lite runtime is much smaller than the full library (around an order of magnitude smaller) but omits certain features like descriptors and reflection. This is particularly useful for apps running on constrained platforms like mobile phones. The compiler will still generate fast implementations of all methods as it does in SPEED mode. Generated classes will only implement the MessageLite interface in each language, which provides only a subset of the methods of the full Message interface.协议缓冲区编译器将生成仅依赖于“精简版”运行时库的类(libprotobuf-lite而非libprotobuf)。精简版运行时比完整库要小得多(大约小一个数量级),但省略了某些功能,例如描述符和反射。这对于在受限平台(例如手机)上运行的应用程序特别有用。编译器仍将像在SPEED模式下一样快速生成所有方法的实现。生成的类将仅以每种语言实现MessageLite接口,该接口仅提供完整Message接口方法的子集。
option optimize_for = CODE_SIZE;
  • cc_enable_arenas (file option): Enables arena allocation for C++ generated code.为C ++生成的代码启用arena allocation
  • objc_class_prefix (file option): Sets the Objective-C class prefix which is prepended to all Objective-C generated classes and enums from this .proto. There is no default. You should use prefixes that are between 3-5 uppercase characters as recommended by Apple. Note that all 2 letter prefixes are reserved by Apple.设置Objective-C类的前缀,该前缀将附加到所有Objective-C生成的类以及此.proto的枚举。没有默认值。您应该使用Apple推荐的3-5个大写字母之间的前缀。请注意,所有2个字母前缀均由Apple保留。
  • deprecated (field option): If set to true, indicates that the field is deprecated and should not be used by new code. In most languages this has no actual effect. In Java, this becomes a @Deprecated annotation. In the future, other language-specific code generators may generate deprecation annotations on the field's accessors, which will in turn cause a warning to be emitted when compiling code which attempts to use the field. If the field is not used by anyone and you want to prevent new users from using it, consider replacing the field declaration with a reserved statement.如果设置为true,则表明该字段已弃用,并且不应由新代码使用。在大多数语言中,这没有实际效果。在Java中,这成为@Deprecated注释。将来,其他特定于语言的代码生成器可能会在字段的访问器上生成弃用注释,这反过来将导致在编译尝试使用该字段的代码时发出警告。如果该字段未被任何人使用,并且您想阻止新用户使用该字段,请考虑使用保留语句替换该字段声明。
int32 old_field = 6 [deprecated = true];

Custom Options

Protocol Buffers also allows you to define and use your own options. This is an advanced feature which most people don't need. If you do think you need to create your own options, see the Proto2 Language Guide for details. Note that creating custom options uses extensions, which are permitted only for custom options in proto3.协议缓冲区还允许您定义和使用自己的选项。这是大多数人不需要的高级功能。如果您确实需要创建自己的选项,请参阅《Proto2 Language Guide》以了解详细信息。请注意,创建自定义选项使用扩展名,扩展名仅适用于proto3中的自定义选项。

Generating Your Classes

To generate the Java, Python, C++, Go, Ruby, Objective-C, or C# code you need to work with the message types defined in a .proto file, you need to run the protocol buffer compiler protoc on the .proto. If you haven't installed the compiler, download the package and follow the instructions in the README. For Go, you also need to install a special code generator plugin for the compiler: you can find this and installation instructions in the golang/protobuf repository on GitHub.要生成Java,Python,C ++,Go,Ruby,Objective-C或C#代码,您需要使用.proto文件中定义的消息类型,您需要在.proto上运行协议缓冲区编译器协议。如果尚未安装编译器,请下载软件包并按照自述文件中的说明进行操作。对于Go,您还需要为编译器安装一个特殊的代码生成器插件:您可以在GitHub上的golang / protobuf存储库中找到此代码和安装说明。

The Protocol Compiler is invoked as follows:协议编译器的调用如下:

protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR --go_out=DST_DIR --ruby_out=DST_DIR --objc_out=DST_DIR --csharp_out=DST_DIRpath/to/file.proto
  • IMPORT_PATH specifies a directory in which to look for .proto files when resolving import directives. If omitted, the current directory is used. Multiple import directories can be specified by passing the --proto_path option multiple times; they will be searched in order. -I=IMPORT_PATH can be used as a short form of --proto_path.指定解析导入指令时要在其中查找.proto文件的目录。如果省略,则使用当前目录。可以通过多次传递--proto_path选项来指定多个导入目录。将按顺序搜索它们。 -I = IMPORT_PATH可以用作--proto_path的缩写
  • You can provide one or more output directives:
  • As an extra convenience, if the DST_DIR ends in .zip or .jar, the compiler will write the output to a single ZIP-format archive file with the given name. .jar outputs will also be given a manifest file as required by the Java JAR specification. Note that if the output archive already exists, it will be overwritten; the compiler is not smart enough to add files to an existing archive.为了更加方便,如果DST_DIR以.zip或.jar结尾,则编译器会将输出写入具有给定名称的单个ZIP格式的存档文件。根据Java JAR规范的要求,还将为.jar输出提供清单文件。请注意,如果输出存档已经存在,它将被覆盖;编译器不够智能,无法将文件添加到现有存档中。

  • You must provide one or more .proto files as input. Multiple .proto files can be specified at once. Although the files are named relative to the current directory, each file must reside in one of the IMPORT_PATHs so that the compiler can determine its canonical name.您必须提供一个或多个.proto文件作为输入。可以一次指定多个.proto文件。尽管这些文件是相对于当前目录命名的,但是每个文件都必须位于IMPORT_PATH之一中,以便编译器可以确定其规范名称。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值