使用protbuf3,如何表达类型'Map string (Maybe CustomType)'?
Using protbuf3, how can I express the type 'Map string (Maybe CustomType)'?
我正在尝试在客户端和服务之间共享一个大 dictionary/map。我需要能够双向设置值,并从 dictionary/map 中删除值,而无需每次来回传递整个地图。
我知道我可以使用以下方法创建地图:
map<string, CustomType> cells = 3;
我在这里看到使用 oneof 的建议:
https://github.com/google/protobuf/issues/1606
但是,该错误报告中建议的语法对我来说没有意义:
message Test1 {
oneof a_oneof {
int32 a = 1;
}
}
我该如何测试?我将如何存储 None?
我会尝试创建类似的东西:
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.
"if any" 部分是您正在寻找的魔法。 oneof 定义的 generated C++ code 将提供一个特殊的 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()
returns ONEOFNAME_NOT_SET
if none of the oneof fields are set.
例子
从一条测试消息开始...
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 语言绑定,但是 oneof
功能在您使用的库中应该具有类似的功能。
我正在尝试在客户端和服务之间共享一个大 dictionary/map。我需要能够双向设置值,并从 dictionary/map 中删除值,而无需每次来回传递整个地图。
我知道我可以使用以下方法创建地图:
map<string, CustomType> cells = 3;
我在这里看到使用 oneof 的建议: https://github.com/google/protobuf/issues/1606
但是,该错误报告中建议的语法对我来说没有意义:
message Test1 {
oneof a_oneof {
int32 a = 1;
}
}
我该如何测试?我将如何存储 None?
我会尝试创建类似的东西:
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.
"if any" 部分是您正在寻找的魔法。 oneof 定义的 generated C++ code 将提供一个特殊的 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()
returns ONEOFNAME_NOT_SET
if none of the oneof fields are set.
例子
从一条测试消息开始...
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 语言绑定,但是 oneof
功能在您使用的库中应该具有类似的功能。