我正在尝试在客户和服务之间共享一个大型词典/地图。我需要能够双向设置值,并从字典/地图中删除值,而无需每次来回传递整个映射。
我知道我可以使用:
创建地图map<string, CustomType> cells = 3;
(ProtoBuf3地图的文档)
我看到了在此处使用一种的sugention:https://github.com/google/protobuf/issues/1606
但是,该错误报告中建议的语法对我没有意义:
message Test1 {
oneof a_oneof {
int32 a = 1;
}
}
我将如何测试?我将如何存储?
我会尝试创建类似的东西:
message None{}
message MaybeCustomType{
oneof maybe{
CustomType just = 1;
None none = 2;
}
}
,但我根本不相信这是优雅而正确的解决方案。
我还考虑了完全更改我的架构。
map<string, CustomType> cells = 1;
repeated string deleted_cells = 2;
但是,我不喜欢该解决方案,因为它会产生不确定的情况。如果"单元格"映射和" deleted_cells"映射都出现一个名为" foo"的单元格会发生什么?此外,它将数据从计算中抽象出来。我希望能够将单元格通过一个修改并有可能决定删除单元的函数,因此在我看来,关于单元格删除的信息似乎很自然。
您的语言标签提到了Haskell,但我不确定您要使用哪种库来提供proto3支持,因此我将尝试提供一个通用的答案。
概述
您指出的线程建议将oneof
与单个字段一起使用,因为可以表示null
(实际上是缺少字段)。幸运的是,您无需为此目的创建None
类型,因为它是内置在特定于语言的生成源文件中的。查看" One"的语言指南...
您可以使用特殊情况()或哪个方法(根据您选择的语言)检查单位中的哪个值(如果有)。
"如果有"部分是您要寻找的魔术。一个单一定义的生成的C 代码将提供一种特殊的oneof_name_case()
方法,该方法将告诉您是否设置了其中一个字段...
OneOfNamecase Oneof_name_case()const:返回指示设置哪个字段的枚举。如果没有设置它们,则返回Oneof_name_not_set。
为Java代码生成了类似的方法:getOneofNameCase()
返回ONEOFNAME_NOT_SET
,如果设置了一个单一字段。
示例
从测试消息开始...
message Test1 {
oneof single_field_oneof {
int32 some_int = 1;
}
}
如果您使用的是C ,则可以使用类似于以下代码来处理单个字段...
int main(int argc, char* argv[]) {
Test1 test;
// <Populate message somehow>
if (test.single_field_case() == Test1::kSomeInt) {
std::cout << "Field is set, value is " << test.some_int() << std::endl;
} else {
assert(test.single_field_case() == Test1::SINGLE_FIELD_NOT_SET);
std::cout << "Field is not set" << std::endl;
}
}
无论如何,正如我提到的,我不熟悉Haskell的特定proto3语言绑定,但是oneof
功能在库中应具有类似的功能。