Буферы протокола - уникальный пронумерованный тег - уточнение?
Я использую протокольные буферы, и все работает нормально. за исключением того, что я не понимаю - зачем мне нужны пронумерованные теги в файле proto
:
message SearchRequest {
required string query = 1;
optional int32 page_number = 2;
optional int32 result_per_page = 3;
}
Конечно, я прочитал docs:
Как вы можете видеть, каждое поле в определении сообщения имеет уникальный пронумерованный тег. Эти теги используются для идентификации ваших полей в бинарный формат сообщения и не должен изменяться после вашего сообщения тип используется.
Я не понял, какая разница, если я его изменю. (Я создам новый прото и скомпилирую его - так зачем это волнует?)
В другой статье говорится, что:
Нумерованные поля в прото-определениях устраняют необходимость в версии проверки, которая является одной из явно заявленных мотивов для проектирование и внедрение протокольных буферов. Как разработчик документация утверждает, что протокол был разработан частично, чтобы избежать "уродливых код" для проверки версий протокола:
if (version == 3) {
...
} else if (version > 4) {
if (version == 5) {
...
}
...
}
Вопрос
Это только я, или это совершенно неясно?
позвольте мне спросить об этом по-другому:
Если у меня есть файл proto, подобный вышеприведенному файлу, а затем я меняю его на:
message SearchRequest {
required string query = 3; //reversed order
optional int32 page_number = 2;
optional int32 result_per_page = 1;
}
Какое это дело? Я повторно компилирую и добавляю файл (я делал это несколько раз за последнюю неделю).
что мне не хватает? можете ли вы предоставить человеко-человеческое объяснение для этих пронумерованных тегов?
Ответы
Ответ 1
Пронумерованные теги используются для сопоставления полей при сериализации и десериализации данных.
Очевидно, что если вы измените схему нумерации и примените это изменение как к сериализатору, так и к десериализатору, проблем нет.
Учтите, что если вы сохранили данные с первой схемой нумерации и загрузили ее со второй, попробуйте загрузить query
в result_per_page
, и десериализация, скорее всего, не удастся.
Теперь, почему это полезно?
Скажем, вам нужно добавить еще одно поле в свои данные, долго после того, как схема уже используется:
message SearchRequest {
required string query = 1;
optional int32 page_number = 2;
optional int32 result_per_page = 3;
optional int32 new_data = 4;
}
Поскольку вы явно даете ему число, ваш десериализатор все еще может загружать данные, сериализованные старой схемой нумерации, игнорируя десериализацию несуществующих данных.
Ответ 2
Эти номера полей используются protobuf при кодировании и декодировании. Подробнее см. здесь.
Таким образом, каждое поле имеет тип провода, поэтому int32 имеет тип провода как 0, а номер вашего поля - 2, поэтому он будет закодирован как 0001 0000, т.е. 10 в шестнадцатеричном формате.
И позже, когда его декодировано, его левый сдвиг на 1, что делает его как 001 0000, а последние три lsb решает тип провода, то есть затем выводит его тип int field и rest решает, какое поле в прото, то есть 00010 является 2. Итак, поле 2 проводного типа 0 (int)