不明な 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}}
追加の考慮事項
代替: Any と Interface{}
Any は、最初は未知のメッセージに適したオプションのように見えるかもしれませんが、厳密に定義された構造があり、未知のペイロードのデコードには使用できません。さらに、protowire はその特殊な構造のため、Any には適用できません。
以上がGo で不明な Protobuf メッセージをアンマーシャリングするにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。