your programing

protobuf 3에서 선택적 필드를 정의하는 방법

lovepro 2021. 1. 5. 19:49
반응형

protobuf 3에서 선택적 필드를 정의하는 방법


protobuf (proto3 구문)에 선택적 필드가있는 메시지를 지정해야합니다. proto 2 구문 측면에서 표현하고 싶은 메시지는 다음과 같습니다.

message Foo {
    required int32 bar = 1;
    optional int32 baz = 2;
}

내 이해에서 "선택적"개념이 구문 proto 3에서 제거되었습니다 (필수 개념과 함께). 대안은 명확하지 않지만 기본값을 사용하여 보낸 사람이 필드를 지정하지 않았 음을 나타내면 기본값이 유효한 값 도메인 (예 : 부울 유형을 고려)에 속하는 경우 모호함이 남습니다.

그렇다면 위의 메시지를 어떻게 인코딩해야합니까? 감사합니다.


proto3에서 모든 필드는 "선택 사항"입니다 (발신자가 설정에 실패해도 오류가 아님). 그러나 필드는 더 이상 "nullable"이 아닙니다. 필드가 명시 적으로 기본값으로 설정되는 것과 전혀 설정되지 않은 것 사이의 차이를 구분할 방법이 없기 때문입니다.

"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 내부 포함)가 proto3에서 제거 된 proto2 기능에 크게 의존하므로 전환되지 않을 가능성이 높습니다. 따라서 가까운 미래에 계속 사용하는 것이 안전합니다.


한 가지 방법은 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()) { ... }


Kenton의 답변에 따르면 더 간단하면서도 작동하는 솔루션은 다음과 같습니다.

message Foo {
    oneof optional_baz { // "optional_" prefix here just serves as an indicator, not keyword in proto2
        int32 baz = 1;
    }
}

To expand on @cybersnoopy 's suggestion here

if you had a .proto file with a message like so:

message Request {
    oneof option {
        int64 option_value = 1;
    }
}

You can make use of the case options provided (java generated code):

So we can now write some code as follows:

Request.OptionCase optionCase = request.getOptionCase();
OptionCase optionNotSet = OPTION_NOT_SET;

if (optionNotSet.equals(optionCase)){
    // value not set
} else {
    // value set
}

you can find if one has been initialized by comparing the references with the default instance:

GRPCContainer container = myGrpcResponseBean.getContainer();
if (container.getDefaultInstanceForType() != container) {
...
}

Another way is that you can use bitmask for each optional field. and set those bits if values are set and reset those bits which values are not set

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;
}

On parsing check for value of bitMask.

if (bitMask & baz_present)
    baz is present

if (bitMask & baz1_present)
    baz1 is present

ReferenceURL : https://stackoverflow.com/questions/42622015/how-to-define-an-optional-field-in-protobuf-3

반응형