ホームページ > バックエンド開発 > Golang > Go で不明な Protobuf メッセージをアンマーシャリングするにはどうすればよいですか?

Go で不明な Protobuf メッセージをアンマーシャリングするにはどうすればよいですか?

Barbara Streisand
リリース: 2024-11-30 09:21:13
オリジナル
945 人が閲覧しました

How Can I Unmarshal Unknown Protobuf Messages in Go?

不明な Protobuf メッセージのアンマーシャリングの落とし穴

proto.Unmarshal がインターフェース タイプを処理できないことは、理解することが重要な側面です。そのメソッド シグネチャでは、具体的なプロトバッファ型によって実装される proto.Message 引数を渡すことが規定されています。

課題の克服

追加のコンテキストが欠落している生のプロトバッファ ペイロードを処理する場合、バイトスライスと一緒に少なくともいくつかの識別情報(文字列や数値など)を含めることが重要です。この情報は、特定のプロトバッファーの具体的なメッセージにマッピングするために使用できます。次に、switch ステートメントを使用して適切な型をインスタンス化し、それを Unmarshal に渡すことができます。

switch atLeastSomething {
    case "foo":
        message = &mypb.Foo{}
    case "bar":
        message = &mypb.Bar{}
}
_ = proto.Unmarshal(data, message)
ログイン後にコピー

予測不能の受け入れ: 完全に未知のメッセージのデコード

まれに、まったく未知のプロトバッファ ペイロードが発生する可能性があります。 protowire パッケージは、固有の制限はありますが、そこから一部の情報を抽出するソリューションを提供します。ペイロードのコンテンツは取得できますが、セマンティクスは弱くなります。

実装の詳細

不明なプロト メッセージの簡略化されたパーサーは次のとおりです。

func parseUnknown(b []byte) []Field {
    // Data model
    type Field struct {
        Tag Tag
        Val Val
    }
    type Tag struct {
        Num int32
        Type protowire.Type
    }
    type Val struct {
        Payload interface{}
        Length  int
    }
    // Parsing algorithm
    fields := make([]Field, 0)
    for len(b) > 0 {
        n, t, fieldlen := protowire.ConsumeField(b)
        if fieldlen < 1 {
            return nil
        }
        ... // Parsing logic
        fields = append(fields, field)
        b = b[fieldlen:]
    }
    return fields
}
ログイン後にコピー

サンプル入力と出力

サンプル入力の場合:

message Foo {
  string a = 1;
  string b = 2;
  Bar bar = 3;
}
message Bar {
  string c = 1;
}
&test.Foo{A: "A", B: "B", Bar: &test.Bar{C: "C"}}
ログイン後にコピー

出力は次のようになります:

Field{Tag:Tag{Num:1, Type:2}, Val:Val{Payload:[]uint8{0x41}, Length:1}}
Field{Tag:Tag{Num:2, Type:2}, Val:Val{Payload:[]uint8{0x42}, Length:1}}
Field{Tag:Tag{Num:1, Type:2}, Val:Val{Payload:[]uint8{0x43}, Length:1}}
Field{Tag:Tag{Num:3, Type:2}, Val:Val{Payload:[]Field{Field{Tag:Tag{Num:1, Type:2}, Val:Val{Payload:[]uint8{0x43}, Length:1}}}, Length:3}}
ログイン後にコピー

追加の考慮事項

  • サブメッセージは、有効な場合、再帰的に解析され、保存されます。それ以外の場合、バイトはそのまま保存されます。
  • 繰り返しフィールドは明示的に処理されませんが、解析後の繰り返しの Tag.Num 値から推測できます。
  • マップは意味的に同等であることが期待されます。キーと値のペアが繰り返されています。
  • 情報の 1 つが失われ、セットのみが保持される可能性があります。 value.

代替: Any と Interface{}

Any は、最初は未知のメッセージに適したオプションのように見えるかもしれませんが、厳密に定義された構造があり、未知のペイロードのデコードには使用できません。さらに、protowire はその特殊な構造のため、Any には適用できません。

以上がGo で不明な Protobuf メッセージをアンマーシャリングするにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート