Ich muss eine Nachricht mit einem optionalen Feld in protobuf (proto3-Syntax) angeben. In Bezug auf die Proto 2-Syntax ist die Nachricht, die ich ausdrücken möchte, ungefähr so:
message Foo {
required int32 bar = 1;
optional int32 baz = 2;
}
Nach meinem Verständnis wurde das "optionale" Konzept aus Syntax Proto 3 entfernt (zusammen mit dem erforderlichen Konzept). Obwohl die Alternative nicht klar ist: Wenn Sie den Standardwert verwenden, um anzugeben, dass kein Feld vom Absender angegeben wurde, bleibt eine Mehrdeutigkeit, wenn der Standardwert zur Domäne der gültigen Werte gehört (z. B. ein boolescher Typ).
Wie soll ich die obige Nachricht verschlüsseln? Vielen Dank.
optional
Antworten:
Seit Protobuf Release 3.12 unterstützt proto3 die Verwendung des
optional
Schlüsselworts (genau wie in proto2), um Informationen zum Vorhandensein eines Skalarfelds zu erhalten.syntax = "proto3"; message Foo { int32 bar = 1; optional int32 baz = 2; }
Für das obige Feld wird eine
has_baz()
/hasBaz()
-Methode generiertoptional
, genau wie in proto2.Unter der Haube behandelt protoc ein
optional
Feld effektiv so , als ob es mit einemoneof
Wrapper deklariert worden wäre , wie die Antwort von CyberSnoopy nahe legt:message Foo { int32 bar = 1; oneof optional_baz { int32 baz = 2; } }
Wenn Sie diesen Ansatz bereits verwendet haben, können Sie Ihre Nachrichtendeklarationen bereinigen (von
oneof
zu wechselnoptional
), da das Drahtformat dasselbe ist.Die
optional
wichtigsten Details zur Feldpräsenz und in proto3 finden Sie im Anwendungshinweis: Feldpräsenzdokument .In Version 3.12 erfordert diese Funktionalität die Übergabe des
--experimental_allow_proto3_optional
Flags an protoc. Die Feature-Ankündigung besagt , dass es "hoffentlich in 3.13 allgemein verfügbar sein wird".Update Oktober 2020: Die Funktion wird in Version 3.13 weiterhin als experimentell (Flag erforderlich) betrachtet .
quelle
optional int xyz
: 1)has_xyz
erkennt, ob der optionale Wert eingestellt wurde 2) setztclear_xyz
den Wert zurück. Weitere Infos hier: github.com/protocolbuffers/protobuf/blob/master/docs/…In proto3 sind alle Felder "optional" (insofern ist es kein Fehler, wenn der Absender sie nicht festlegt). Felder sind jedoch nicht mehr "nullbar", da es keinen Unterschied zwischen einem Feld gibt, das explizit auf seinen Standardwert gesetzt wurde, und einem Feld, das überhaupt nicht gesetzt wurde.
Wenn Sie einen "Null" -Status benötigen (und es keinen Wert außerhalb des Bereichs gibt, den Sie dafür verwenden können), müssen Sie diesen stattdessen als separates Feld codieren. Zum Beispiel könnten Sie tun:
message Foo { bool has_baz = 1; // always set this to "true" when using baz int32 baz = 2; }
Alternativ können Sie Folgendes verwenden
oneof
:message Foo { oneof baz { bool baz_null = 1; // always set this to "true" when null int32 baz_value = 2; } }
Die
oneof
Version ist expliziter und effizienter, erfordert jedoch Verständnis für die Funktionsweise vononeof
Werten.Schließlich ist eine andere völlig vernünftige Option, bei proto2 zu bleiben. Proto2 ist nicht veraltet, und tatsächlich hängen viele Projekte (einschließlich innerhalb von Google) sehr stark von Proto2-Funktionen ab, die in Proto3 entfernt wurden, daher werden sie wahrscheinlich nie wechseln. Es ist also sicher, es auf absehbare Zeit weiter zu verwenden.
quelle
Eine Möglichkeit besteht darin,
oneof
wie in der akzeptierten Antwort vorgeschlagen zu verwenden.Eine andere Möglichkeit besteht darin, Wrapper-Objekte zu verwenden. Sie müssen sie nicht selbst schreiben, da Google sie bereits bereitstellt:
Fügen Sie oben in Ihrer .proto-Datei diesen Import hinzu:
import "google/protobuf/wrappers.proto";
Jetzt können Sie für jeden einfachen Typ spezielle Wrapper verwenden:
DoubleValue FloatValue Int64Value UInt64Value Int32Value UInt32Value BoolValue StringValue BytesValue
Um die ursprüngliche Frage zu beantworten, könnte die Verwendung eines solchen Wrappers folgendermaßen aussehen:
message Foo { int32 bar = 1; google.protobuf.Int32Value baz = 2; }
Jetzt kann ich zum Beispiel in Java Dinge tun wie:
if(foo.hasBaz()) { ... }
quelle
baz=null
und wannbaz
nicht übergeben wird, in beiden FällenhasBaz()
sagtfalse
!Basierend auf Kentons Antwort sieht eine einfachere und dennoch funktionierende Lösung so aus:
message Foo { oneof optional_baz { // "optional_" prefix here just serves as an indicator, not keyword in proto2 int32 baz = 1; } }
quelle
None
(in C #). Die Sprache Ihrer Wahl finden Sie im Aufzählungstyp.Um den Vorschlag von @cybersnoopy hier zu erweitern
Wenn Sie eine .proto-Datei mit einer Nachricht wie der folgenden hatten:
message Request { oneof option { int64 option_value = 1; } }
Sie können die bereitgestellten Falloptionen verwenden (von Java generierter Code) :
So können wir jetzt folgenden Code schreiben:
Request.OptionCase optionCase = request.getOptionCase(); OptionCase optionNotSet = OPTION_NOT_SET; if (optionNotSet.equals(optionCase)){ // value not set } else { // value set }
quelle
Es gibt einen guten Beitrag dazu: https://itnext.io/protobuf-and-null-support-1908a15311b6
Die Lösung hängt von Ihrem tatsächlichen Anwendungsfall ab:
Teilaktualisierung behandeln
Unterstützung null
quelle
Eine andere Möglichkeit besteht darin, dass Sie für jedes optionale Feld eine Bitmaske verwenden können. und setzen Sie diese Bits, wenn Werte gesetzt sind, und setzen Sie die Bits zurück, deren Werte nicht gesetzt sind
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; }
Überprüfen Sie beim Parsen den Wert von bitMask.
if (bitMask & baz_present) baz is present if (bitMask & baz1_present) baz1 is present
quelle
Sie können feststellen, ob eine initialisiert wurde, indem Sie die Referenzen mit der Standardinstanz vergleichen:
GRPCContainer container = myGrpcResponseBean.getContainer(); if (container.getDefaultInstanceForType() != container) { ... }
quelle