4

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

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

map<string, CustomType> cells = 3;

protobuf3 地图的文档

我在这里看到使用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”映射中,会发生什么?此外,它将数据从计算中抽象出来。我希望能够将一个单元格传递给一个修改并可能决定删除单元格的函数,因此对我来说,关于单元格删除的信息存储在单元格本身附近似乎很自然。

4

1 回答 1

1

您的语言标签提到了 haskell,但我不确定您使用哪个库实现来提供 proto3 支持,所以我会尝试提供一个通用的答案。

概述

您指向的线程建议使用oneof单个字段,因为它可以表示 a null(实际上没有该字段)。幸运的是,您不需要None为此目的创建类型,因为它内置于特定语言生成的源文件中。查看其中一个的语言指南...

您可以使用特殊的 case() 或 WhichOneof() 方法检查 oneof 中设置的值(如果有),具体取决于您选择的语言。

“如果有”部分是您正在寻找的魔法。为 oneof 定义生成的C++ 代码将提供一种特殊oneof_name_case()方法,该方法将告诉您是否已设置其中一个字段...

OneofNameCase oneof_name_case() const:返回指示设置了哪个字段的枚举。如果没有设置它们,则返回 ONEOF_NAME_NOT_SET。

为 Java 代码生成类似的方法:如果没有设置 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 语言绑定,但该oneof功能应该在您使用的库中具有类似的功能。

于 2017-10-05T15:05:44.170 回答