15

我一直在为一个项目实施 IPC 的 protobufs。出于某种原因,未设置/序列化设置为 0 的值。对于上下文,.proto 文件包含以下消息:

syntax = "proto3";

enum SetGet {
    SET = 0;
    GET = 1;
}

message State {
    SetGet setget = 1;
    double x = 2;
    double y = 3;
    double depth = 4;
    double yaw = 5;
    double pitch = 6;
    double roll = 7; 
}

我使用 protoc 将文件编译为 Python _pb2 文件,然后尝试运行以下测试脚本:

import filename_pb2 as pb

state = pb.State()
state.x = 0
state.y = 0
state.depth = 0
state.yaw = 0
state.pitch = 0
state.roll = 0
state.setget = pb.SET

print("State: {}".format(state))

state2 = pb.State()
state2.ParseFromString(state.SerializeToString())

print("State2: {}".format(state2))

当我运行它时,会打印以下输出:

State: 
State2: 

似乎没有设置任何内容,或者零值被某种方式忽略了。但是,当我将值(x、y、深度等)更改为非零值(例如 0.1)时,我得到以下预期结果:

State: x: 0.1
y: 0.1
depth: 0.1
yaw: 0.1
pitch: 0.1
roll: 0.1

State2: x: 0.1
y: 0.1
depth: 0.1
yaw: 0.1
pitch: 0.1
roll: 0.1

即使数字被打印出来,由于某种原因,枚举仍然不是。为什么 protobuf 会发生这种情况?默认情况下 double 类型为 0,因此 protobuf 序列化程序通过忽略它们来节省空间?那么,为什么在解析 State2 时它们没有被恢复呢?我错过了文档中的某些行吗?提前致谢!

——蒂姆

4

3 回答 3

15

是的,0 是默认值。文档中明确提到了这种情况:

请注意,对于标量消息字段,一旦解析了消息,就无法判断一个字段是显式设置为默认值(例如布尔值是否设置为 false)还是根本没有设置:您应该在定义消息类型时请注意。例如,如果您不希望在默认情况下也发生该行为,则不要在设置为 false 时打开某些行为的布尔值。另请注意,如果标量消息字段设置为其默认值,则该值将不会在线上序列化。

于 2017-11-19T05:26:58.100 回答
4

零是 protobuf 中数字的默认值,空字符串是字符串的默认值。为了提高效率,默认值不会通过网络传输。

如果您真的希望能够判断它是否被明确设置,请不要将默认零用于实际操作:

enum SetGet {
    NONE = 0;
    SET = 1;
    GET = 2;
}

请记住,这将导致网络上的额外流量,并且由于您只是真正担心要打印的内容,因此您也可以理解零是默认值,或者编写自己的打印例程来输出所有内容。

于 2017-11-19T05:30:21.503 回答
2

这最近发生了变化;proto3 现在支持存在跟踪,通过添加optional关键字来启用:

message State {
    optional SetGet setget = 1;
    optional double x = 2;
    optional double y = 3;
    optional double depth = 4;
    optional double yaw = 5;
    optional double pitch = 6;
    optional double roll = 7; 
}

来自https://github.com/protocolbuffers/protobuf/blob/master/CHANGES.txt

2021-02-05 版本 3.15.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

协议编译器

  • proto3 的可选字段默认启用,不再需要 --experimental_allow_proto3_optional 标志。

这是这个的RTM:

2020-05-12 版本 3.12.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

协议编译器

  • [实验性] proto3 中的单一非消息类型字段现在支持存在跟踪。这是通过添加“可选”字段标签并将 --experimental_allow_proto3_optional 标志传递给 protoc 来启用的。
于 2021-03-31T16:01:43.777 回答