我正在尝试在客户端和服务之间共享一个大型字典/ map 。我需要能够双向设置值,并从字典/ map 中删除值,而无需每次都来回传递整个 map 。
我知道我可以使用以下方法创建 map :
map<string, CustomType> cells = 3;
(Docs for protobuf3 maps)
我看到使用 oneof 的建议这里:
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;
但是我不喜欢那个解决方案,因为它会创建一个未定义的案例。如果一个名为“foo”的单元格同时出现在“cells”映射和“deleted_cells”映射中,会发生什么?此外,它将数据从计算中抽象出来。我希望能够将一个单元格传递给一个修改并可能决定删除单元格的函数,因此对我来说,关于单元格删除的信息存储在单元格本身附近似乎很自然。
最佳答案
您的语言标签提到了 haskell,但我不确定您使用哪个库实现来提供 proto3 支持,所以我会尝试提供一个通用的答案。
概述
您指出的线程建议使用 oneof
使用单个字段,因为它可以表示 null
(真的没有领域)。幸运的是,您不需要创建 None
用于此目的的类型,因为它内置在特定于语言的生成源文件中。看看Language Guide for oneof ...
You can check which value in a oneof is set (if any) using a special case() or WhichOneof() method, depending on your chosen language.
“如果有”部分是您正在寻找的魔法。 generated C++ code对于 oneof 定义,将提供一个特殊的
oneof_name_case()
该方法将告诉您是否已设置其中一个字段...OneofNameCase oneof_name_case() const: Returns the enum indicating which field is set. Returns ONEOF_NAME_NOT_SET if none of them is set.
一个类似的方法是generated for Java code :
getOneofNameCase()
返回 ONEOFNAME_NOT_SET
如果没有设置 oneof 字段。例子
从测试消息开始...
message Test1 {
oneof single_field_oneof {
int32 some_int = 1;
}
}
如果您使用的是 C++,您可以使用类似于以下的代码来处理 oneof 字段...
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 语言绑定(bind),但
oneof
功能应该在您正在使用的库中具有类似的功能。
关于haskell - 使用 protobuf 3,如何表达类型 'Map string (Maybe CustomType)' ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46443201/