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 должно быть одинаковым в обоих местах.