其他语言见官方文档:https://developers.google.com/protocol-buffers/docs/javatutorial#scalar
.proto Type | Notes | Java Type |
---|---|---|
double | double | |
float | float | |
int32 | 使用可变长编码,编码负数的效率很低——如果你的字段可能有负数,使用sint32代替 | int |
int64 | 使用可变长编码,编码负数的效率很低——如果你的字段可能有负数,使用sint64代替 | long |
uint32 | 使用可变长度编码 | int[1] |
uint64 | 使用可变长度编码 | long[1] |
sint32 | 使用可变长编码,带符号的int值。它们比普通int32编码负数更有效 | int |
sint64 | 使用可变长编码,带符号的int值。它们比普通int64编码负数更有效 | long |
fixed32 | 总是4个字节,如果值经常大于2的28次方,则比uint32更有效 | int[1] |
fixed64 | 总是8个字节,如果值经常大于2的56次方,则比uint64更有效 | long[1] |
sfixed32 | 总是4个字节 | int |
sfixed64 | 总是8个字节 | long |
bool | boolean | |
string | 字符串必须始终包含UTF-8编码或7位ASCII文本,且长度不能超过2的32次方 | String |
bytes | 可以包含不超过2的32次方的任意字节序列 | ByteString |
在解析消息时,如果编码的消息不包含特定的单个元素,则解析对象中的相应字段将设置为该字段的默认值;
类型 | 默认值 |
---|---|
string | 空字符串 |
bytes | 空字符 |
bool | false |
num | 0 |
enums | 对于枚举,默认值是第一个定义的枚举值,该值必须为0 |
message | 与对应编程语言有关 |
重复字段 | 重复字段的默认值为空(通常在适当的语言中为空列表) |
请注意,对于标量消息字段(标准类型字段),一旦消息被解析,就无法判断字段是显式设置为默认值(例如,是否将布尔值设置为 false),还是根本没有设置,在定义消息类型时应该牢记这一点。例如,如果您不希望某些行为在默认情况下也发生,那么就不要设置一个布尔值,该布尔值在设置为 false 时可以开启某些行为。还要注意,如果将标量消息字段设置为默认值,则该值将不会在连接上序列化。
限定字段的值在一个列表中;
在定义消息类型时,您可能希望它的某个字段只有一个预定义的值列表。比如某件商品几种确定的尺码,您可以非常简单地做到这一点,方法是在消息定义中为每个可能的值添加一个带常量的枚举。
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 enum 的第一个常量映射为0,每个 enum 定义必须包含一个常量,该常量映射为0作为它的第一个元素。这是因为:
枚举数常数必须在32位整数的范围内。由于枚举值在线路上使用变容编码,因此负值效率低,因此不推荐使用。可以在消息定义中定义枚举(如上面的例子所示) ,也可以在消息定义中重用这些枚举。 如果在.proto文件中使用枚举,在使用protobuf编译器编译之后,会生成C++、Java对应的枚举,Python有一个特殊的EnumDescriptor类; 警告:生成的代码可能会受到特定于语言的枚举数量限制;
假如你需要给不同的枚举常量设置为相同的值,那么你必须设置别名,这样做必须将 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.
}
}
与预留字段类似;
enum Foo {
reserved 2, 15, 9 to 11, 40 to max;
reserved "FOO", "BAR";
}
注意,不能在同一保留语句中混合字段名和数值。
message SearchResponse {
repeated Result results = 1;
}
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}
这个部分不太明白!!!
注意,这个特性在Java中是不可用的!
上面的例子中,Result消息和SearchResponse消息定义在同一个文件中,可以直接使用,如果想要使用其他 .proto 文件中定义的消息,可以将这些文件导入!
import "myproject/other_protos.proto";
默认情况下你只能使用直接导入的 .proto 文件中的定义,然而,有时候你需要移动一个 .proto 文件到一个新的位置,可以不直接移动 .proto 文件,只需放入一个伪 .proto 文件在老的位置,然后使用import public转向新的位置。import public 依赖性会通过任意导入包含import public声明的proto文件传递。例如:
// new.proto
// All definitions are moved here
// old.proto
// This is the proto that all clients are importing.
// 这是所有客户端正在导入的proto
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
// 你可以使用来自new.proto的和old.proto的定义,而不是other.proto
通过在编译器命令行参数中使用-I/--proto_path
protocal 编译器会在指定目录搜索要导入的文件。如果没有给出标志,编译器会搜索编译命令被调用的目录。通常你只要指定proto_path标志为你的工程根目录就好,并且指定好导入的正确名称就好。
在你的proto3消息中导入proto2的消息类型也是可以的,反之亦然,然后proto2枚举不可以直接在proto3的标识符中使用(如果仅仅在proto2消息中使用是可以的);