haskell – 使用protbuf3,如何表达“Map string(Maybe CustomType)”类型?

我想在客户端和服务之间共享一个大的字典/地图.我需要能够双向设置值,并从字典/地图中删除值,而不是每次都来回传递整个地图.

我知道我可以使用以下方法创建地图:

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”的单元格出现在“单元格”地图和“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_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:如果没有设置oneof字段,则getOneofNameCase()返回ONEOFNAME_NOT_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语言绑定,但其中一个功能应该在您正在使用的库中具有类似的功能.

点赞