Мне нужно указать сообщение с необязательным полем в protobuf (синтаксис proto3). С точки зрения синтаксиса proto 2, сообщение, которое я хочу выразить, выглядит примерно так:
message Foo {
required int32 bar = 1;
optional int32 baz = 2;
}
Насколько я понимаю, «необязательная» концепция была удалена из синтаксиса proto 3 (вместе с необходимой концепцией). Хотя неясна альтернатива - использование значения по умолчанию, чтобы указать, что поле не было указано отправителем, оставляет неоднозначность, если значение по умолчанию принадлежит домену допустимых значений (рассмотрим, например, логический тип).
Итак, как я должен закодировать сообщение выше? Спасибо.
optional
Ответы:
Начиная с версии 3.12 protobuf, proto3 поддерживает использование
optional
ключевого слова (как и в proto2) для предоставления информации о наличии скалярного поля.syntax = "proto3"; message Foo { int32 bar = 1; optional int32 baz = 2; }
A
has_baz()
/hasBaz()
метод создается дляoptional
поля выше, так же , как это было в proto2.Под капотом protoc эффективно обрабатывает
optional
поле, как если бы оно было объявлено с помощьюoneof
оболочки, как следует из ответа CyberSnoopy :message Foo { int32 bar = 1; oneof optional_baz { int32 baz = 2; } }
Если вы уже использовали этот подход, вы можете очистить объявления сообщений (переключитесь с
oneof
наoptional
), поскольку формат проводов такой же.Вы можете найти подробные сведения о присутствии на местах и
optional
в proto3 в Примечании по применению: присутствие на местах документ о .В версии 3.12 эта функция требует передачи
--experimental_allow_proto3_optional
флага в protoc. В объявлении говорится, что она будет «общедоступной, надеюсь, в версии 3.13».Обновление за октябрь 2020 г. Эта функция по-прежнему считается экспериментальной (требуется флаг) в версии 3.13 .
источник
optional int xyz
: 1)has_xyz
определяет, было ли установлено дополнительное значение; 2)clear_xyz
сбрасывает значение. Подробнее здесь: github.com/protocolbuffers/protobuf/blob/master/docs/…В proto3 все поля являются «необязательными» (это не является ошибкой, если отправитель не может их установить). Но поля больше не являются «допускающими значение NULL», поскольку нет способа отличить поле, явно установленное на значение по умолчанию, и то, что оно не было установлено вообще.
Если вам нужно «нулевое» состояние (и нет значения вне диапазона, которое вы можете использовать для этого), вам вместо этого нужно будет закодировать его как отдельное поле. Например, вы можете:
message Foo { bool has_baz = 1; // always set this to "true" when using baz int32 baz = 2; }
В качестве альтернативы вы можете использовать
oneof
:message Foo { oneof baz { bool baz_null = 1; // always set this to "true" when null int32 baz_value = 2; } }
Эта
oneof
версия более ясна и эффективна, но требует понимания того, какoneof
работают значения.Наконец, еще один вполне разумный вариант - придерживаться proto2. Proto2 не является устаревшим, и на самом деле многие проекты (в том числе внутри Google) очень сильно зависят от функций proto2, которые удалены в proto3, поэтому они, вероятно, никогда не переключатся. Так что в обозримом будущем его можно безопасно использовать.
источник
Один из способов - использовать то,
oneof
что предлагается в принятом ответе.Другой - использовать объекты-оболочки. Вам не нужно писать их самостоятельно, поскольку Google уже предоставляет их:
Вверху вашего файла .proto добавьте этот импорт:
import "google/protobuf/wrappers.proto";
Теперь вы можете использовать специальные обертки для каждого простого типа:
DoubleValue FloatValue Int64Value UInt64Value Int32Value UInt32Value BoolValue StringValue BytesValue
Итак, чтобы ответить на исходный вопрос, использование такой оболочки может быть таким:
message Foo { int32 bar = 1; google.protobuf.Int32Value baz = 2; }
Теперь, например, на Java я могу делать такие вещи, как:
if(foo.hasBaz()) { ... }
источник
baz=null
и когдаbaz
не проходит,hasBaz()
говорят оба случаяfalse
!Основываясь на ответе Кентона, более простое, но рабочее решение выглядит так:
message Foo { oneof optional_baz { // "optional_" prefix here just serves as an indicator, not keyword in proto2 int32 baz = 1; } }
источник
None
(в C #) - см. Enum-type для выбранного вами языка.Чтобы расширить предложение @cybersnoopy здесь
если у вас есть файл .proto с таким сообщением:
message Request { oneof option { int64 option_value = 1; } }
Вы можете использовать предоставленные варианты case (код, сгенерированный java) :
Итак, теперь мы можем написать следующий код:
Request.OptionCase optionCase = request.getOptionCase(); OptionCase optionNotSet = OPTION_NOT_SET; if (optionNotSet.equals(optionCase)){ // value not set } else { // value set }
источник
Об этом есть хороший пост: https://itnext.io/protobuf-and-null-support-1908a15311b6
Решение зависит от вашего фактического использования:
Обработка частичного обновления
Поддержка null
источник
Другой способ - использовать битовую маску для каждого необязательного поля. и установить эти биты, если значения установлены, и сбросить те биты, значения которых не установлены
enum bitsV { baz_present = 1; // 0x01 baz1_present = 2; // 0x02 } message Foo { uint32 bitMask; required int32 bar = 1; optional int32 baz = 2; optional int32 baz1 = 3; }
При разборе проверьте значение bitMask.
if (bitMask & baz_present) baz is present if (bitMask & baz1_present) baz1 is present
источник
вы можете узнать, был ли он инициализирован, сравнив ссылки с экземпляром по умолчанию:
GRPCContainer container = myGrpcResponseBean.getContainer(); if (container.getDefaultInstanceForType() != container) { ... }
источник