使用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;

(Docs for protobuf3 maps)

我在这里看到使用 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 codegetOneofNameCase() 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 功能在您使用的库中应该具有类似的功能。