Max*_*axP 61 protocol-buffers protocol-buffers-3
我需要在protobuf(proto3语法)中指定带有可选字段的消息.就proto 2语法而言,我想表达的信息是这样的:
message Foo {
required int32 bar = 1;
optional int32 baz = 2;
}
Run Code Online (Sandbox Code Playgroud)
根据我的理解,"可选"概念已从语法proto 3(以及所需概念)中删除.虽然不清楚替代方法 - 使用默认值来声明尚未从发送方指定字段,但如果默认值属于有效值域,则会留下歧义(例如考虑布尔类型).
那么,我应该如何对上面的消息进行编码?谢谢.
jar*_*obs 99
从 protobuf版本 3.15 开始,proto3 支持使用optional关键字(就像在 proto2 中一样)来提供标量字段存在信息。
syntax = "proto3";
message Foo {
int32 bar = 1;
optional int32 baz = 2;
}
Run Code Online (Sandbox Code Playgroud)
为上面的字段生成了一个has_baz()/hasBaz()方法optional,就像在 proto2 中一样。
在幕后,protoc有效地将optional字段视为使用oneof包装器声明的字段,正如CyberSnoopy 的回答所暗示的那样:
message Foo {
int32 bar = 1;
oneof optional_baz {
int32 baz = 2;
}
}
Run Code Online (Sandbox Code Playgroud)
如果您已经使用过这种方法,那么您现在可以简化您的消息声明(从 切换oneof到optional)和代码,因为有线格式是相同的。
有关现场存在和optionalproto3 的具体细节可以在应用说明中找到:现场存在文档。
历史记录:optional2020 年 4 月 23 日在此评论中首次宣布了对 in proto3 的实验性支持。使用它需要--experimental_allow_proto3_optional在 3.12-3.14 版本中传递 protoc标志。
Ken*_*rda 80
在proto3中,所有字段都是"可选的"(因为如果发送方未能设置它们,则不是错误).但是,字段不再是"可空的",因为没有办法区分显式设置为默认值的字段与根本未设置的字段之间的区别.
如果您需要一个"null"状态(并且没有可用于此的超出范围的值),那么您将需要将其编码为单独的字段.例如,你可以这样做:
message Foo {
bool has_baz = 1; // always set this to "true" when using baz
int32 baz = 2;
}
Run Code Online (Sandbox Code Playgroud)
或者,您可以使用oneof:
message Foo {
oneof baz {
bool baz_null = 1; // always set this to "true" when null
int32 baz_value = 2;
}
}
Run Code Online (Sandbox Code Playgroud)
该oneof版本在线路上更明确,更高效,但需要了解oneof值如何工作.
最后,另一个完全合理的选择是坚持使用proto2.Proto2并没有被弃用,事实上很多项目(包括Google内部)都非常依赖proto2中删除的proto2功能,因此它们可能永远不会切换.因此,在可预见的将来继续使用它是安全的.
VM4*_*VM4 57
一种方法是使用oneof在接受的答案中建议的方式.
另一个是使用包装器对象.你不需要像google已经提供的那样自己编写它们:
在.proto文件的顶部添加此导入:
import "google/protobuf/wrappers.proto";
现在,您可以为每种简单类型使用特殊包装:
DoubleValue
FloatValue
Int64Value
UInt64Value
Int32Value
UInt32Value
BoolValue
StringValue
BytesValue
Run Code Online (Sandbox Code Playgroud)
所以要回答原始问题,这种包装的用法可能是这样的:
message Foo {
int32 bar = 1;
google.protobuf.Int32Value baz = 2;
}
Run Code Online (Sandbox Code Playgroud)
现在,例如在Java中我可以做类似的事情:
if(foo.hasBaz()) { ... }
Cyb*_*opy 18
根据Kenton的回答,一个更简单但更有效的解决方案如下:
message Foo {
oneof optional_baz { // "optional_" prefix here just serves as an indicator, not keyword in proto2
int32 baz = 1;
}
}
Run Code Online (Sandbox Code Playgroud)
在此处扩展@cybersnoopy 的建议
如果您有一个带有如下消息的 .proto 文件:
message Request {
oneof option {
int64 option_value = 1;
}
}
Run Code Online (Sandbox Code Playgroud)
您可以使用提供的案例选项(java 生成的代码):
所以我们现在可以写一些代码如下:
Request.OptionCase optionCase = request.getOptionCase();
OptionCase optionNotSet = OPTION_NOT_SET;
if (optionNotSet.equals(optionCase)){
// value not set
} else {
// value set
}
Run Code Online (Sandbox Code Playgroud)
只需使用:
syntax = "proto3";
message Hello {
int64 required_id = 1;
optional int64 optional_id = 2;
}
Run Code Online (Sandbox Code Playgroud)
在 Go 中,它构建结构体
type Hello struct {
...
RequiredId int64 ...
OptionalId *int64 ...
...
}
Run Code Online (Sandbox Code Playgroud)
您可以轻松检查nil并区分默认值(零)和未设置值(nil)。
这里的大多数答案都已经过时并且不必要地复杂。