Protobuf3: Как описать карту повторяющейся строки?

Официальная документация о типе карты гласит:

map<key_type, value_type> map_field = N;

... где key_type может быть любым целочисленным или строковым типом (то есть, любым скалярным типом, кроме типов с плавающей запятой и байтов). Тип value_type может быть любого типа.

Я хочу определить map<string, repeated string> поле, но это кажется незаконным на моем libprotoc 3.0.0, который жалуется Expected ">", Поэтому мне интересно, есть ли способ поместить повторную строку в карту.

Возможный обходной путь может быть:

message ListOfString {
    repeated string value = 1;
}

// Then define:
map<string, ListOfString> mapToRepeatedString = 1;

Но ListOfString здесь выглядит избыточным.

1 ответ

Решение

У меня была такая же потребность, и я получил ту же ошибку. Я не верю, что это возможно. Вот соответствующие определения BNF из спецификации языка.

https://developers.google.com/protocol-buffers/docs/reference/proto3-spec

messageType = [ "." ] { ident "." } messageName
mapField = "map" "<" keyType "," type ">" mapName "=" fieldNumber [ "["fieldOptions "]" ] ";"
type = "double" | "float" | "int32" | "int64" | "uint32" | "uint64"
  | "sint32" | "sint64" | "fixed32" | "fixed64" | "sfixed32" | "sfixed64"
  | "bool" | "string" | "bytes" | messageType | enumType
messageName = ident
ident = letter { letter | decimalDigit | "_" }
field = [ "repeated" ] type fieldName "=" fieldNumber [ "[" fieldOptions "]" ] ";"

"Повторное" ключевое слово появляется только в определении поля. Определение карты требует "тип", который не включает повторное ключевое слово.

Это означает, что есть несколько вариантов.

  • Вы можете создать оболочку для повторяющегося значения, как вы указали.
  • Существует более старый способ, которым люди определяют карты, который является более обременительным, но эквивалентным. Это пример обратной совместимости из руководства по языкам. https://developers.google.com/protocol-buffers/docs/proto3#maps
        message MapFieldEntry {
          key_type key = 1;
          повторное значение value_type = 2;
        }
        повторяется MapFieldEntry map_field = N;
        
    Вам нужно будет преобразовать данные в карту самостоятельно, но это должно быть довольно тривиально в большинстве языков. В Java:
        List  map_field = // Существующий список из protobuf.
        Карта <тип_ключа, список <тип_значения >> = map_field.stream()
            .collect(Collectors.toMap(kv -> kv.key, kv -> kv.value));
    
        
  • Используйте google.protobuf.ListValue https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#listvalue Это коллекция нетипизированных списков из их хорошо известных типов.

Думаю, должно быть так.

message ListOfString {
   repeated string what_ever_name = 1;
}

// Then define:
map<string, ListOfString> what_ever_name = 1;

Помните, что what_ever_name должно быть одинаковым в обоих местах.

Другие вопросы по тегам