0
点赞
收藏
分享

微信扫一扫

【Protobuf协议】002-标准类型、默认值、枚举、使用费其他消息类型


目录

​​三、标准类型​​

​​四、默认值​​

​​五、枚举​​

​​1、简单使用​​

​​2、别名​​

​​3、预留值​​

​​六、使用其他消息类型​​

​​1、简单例子​​

​​2、导入定义*​​

​​3、使用proto2消息类型​​

三、标准类型

其他语言见官方文档:​​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 时可以开启某些行为。还要注意,如果将标量消息字段设置为默认值,则该值将不会在连接上序列化。

 

五、枚举

1、简单使用

限定字段的值在一个列表中;

在定义消息类型时,您可能希望它的某个字段只有一个预定义的值列表。比如某件商品几种确定的尺码,您可以非常简单地做到这一点,方法是在消息定义中为每个可能的值添加一个带常量的枚举。

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作为它的第一个元素。这是因为:

  • 必须有一个0值,以便我们可以使用0作为数值默认值;
  • 0值必须是第一个元素,以便与 proto2语义兼容,其中第一个枚举值总是默认值。

枚举数常数必须在32位整数的范围内。由于枚举值在线路上使用变容编码,因此负值效率低,因此不推荐使用。可以在消息定义中定义枚举(如上面的例子所示) ,也可以在消息定义中重用这些枚举。

如果在.proto文件中使用枚举,在使用protobuf编译器编译之后,会生成C++、Java对应的枚举,Python有一个特殊的EnumDescriptor类;

警告:生成的代码可能会受到特定于语言的枚举数量限制;

 

2、别名

假如你需要给不同的枚举常量设置为相同的值,那么你必须设置别名,这样做必须将 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.
}
}

 

3、预留值

与预留字段类似;

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

注意,不能在同一保留语句中混合字段名和数值。

 

六、使用其他消息类型

1、简单例子

message SearchResponse {
repeated Result results = 1;
}

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

 

2、导入定义*

这个部分不太明白!!!

注意,这个特性在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标志为你的工程根目录就好,并且指定好导入的正确名称就好。

 

3、使用proto2消息类型

在你的proto3消息中导入proto2的消息类型也是可以的,反之亦然,然后proto2枚举不可以直接在proto3的标识符中使用(如果仅仅在proto2消息中使用是可以的);

 

 

 

 

 

 

 

 

 

 

 

举报

相关推荐

0 条评论