protocol buffers - google - Cómo definir un campo opcional en protobuf 3
protocol buffers array (4)
Necesito especificar un mensaje con un campo opcional en protobuf (sintaxis proto3). En términos de la sintaxis de proto 2, el mensaje que quiero expresar es algo como:
message Foo {
required int32 bar = 1;
optional int32 baz = 2;
}
Según tengo entendido, el concepto "opcional" se ha eliminado de la sintaxis proto 3 (junto con el concepto requerido). Aunque no queda clara la alternativa: utilizar el valor predeterminado para indicar que no se ha especificado un campo desde el remitente, deja una ambigüedad si el valor predeterminado pertenece al dominio de valores válidos (por ejemplo, considere un tipo booleano).
Entonces, ¿cómo se supone que debo codificar el mensaje anterior? Gracias.
Basada en la respuesta de Kenton, una solución más simple pero que funciona es como:
message Foo {
oneof optional_baz { // "optional_" prefix here just serves as an indicator, not keyword in proto2
int32 baz = 1;
}
}
En proto3, todos los campos son "opcionales" (porque no es un error si el remitente no los configura). Pero, los campos ya no son "anulables", ya que no hay manera de decir la diferencia entre un campo que se establece explícitamente en su valor predeterminado y no se ha establecido en absoluto.
Si necesita un estado "nulo" (y no hay un valor fuera de rango que pueda usar para esto), entonces deberá codificar esto como un campo separado. Por ejemplo, usted podría hacer:
message Foo {
bool has_baz = 1;
int32 baz = 2;
}
Alternativamente, podrías usar oneof
:
message Foo {
oneof baz {
bool baz_null = 1; // always set this to "true" when using
int32 baz_value = 2;
}
}
La versión de oneof
es más explícita y más eficiente en la red, pero requiere comprender cómo funciona uno de los valores.
Finalmente, otra opción perfectamente razonable es seguir con proto2. Proto2 no está en desuso, y de hecho, muchos proyectos (incluso dentro de Google) dependen en gran medida de las características de proto2 que se eliminan en proto3, por lo que probablemente nunca se cambiarán. Por lo tanto, es seguro seguir usándolo en el futuro previsible.
Una forma es usar uno de los oneof
sugeridos en la respuesta aceptada.
Otra es usar objetos de envoltura. No es necesario que las escriba usted mismo, ya que Google ya las proporciona:
En la parte superior de su archivo .proto agregue esta importación:
import "google/protobuf/wrappers.proto";
Ahora puedes usar envoltorios especiales para cada tipo simple:
DoubleValue
FloatValue
Int64Value
UInt64Value
Int32Value
UInt32Value
BoolValue
StringValue
BytesValue
Entonces, para responder a la pregunta original, un uso de tal envoltorio podría ser así:
message Foo {
int32 bar = 1;
google.protobuf.Int32Value baz = 2;
}
Ahora, por ejemplo, en Java puedo hacer cosas como:
if(foo.hasBaz()) { ... }
puede encontrar si se ha inicializado uno comparando las referencias con la instancia predeterminada:
GRPCContainer container = myGrpcResponseBean.getContainer();
if (container.getDefaultInstanceForType() != container) {
...
}