将 protobuf 消息解组到接口{}以促进类型转换是不可行的,因为 proto.Unmarshal 函数需要一个类型的参数proto.Message,具体protobuf类型的接口
如果至少有一些上下文信息(例如字符串或数字)伴随字节切片,您可以使用该信息来映射到预期的protobuf 类型并在将其传递给 proto.Unmarshal 之前实例化它:
func decodeWithMetadata(data []byte, identifier string) error { var message proto.Message switch identifier { case "foo": message = &mypb.Foo{} case "bar": message = &mypb.Bar{} } if err := proto.Unmarshal(data, message); err != nil { return err } log.Printf("%v\n", data) return nil }
但是,如果字节有效负载完全未知,请考虑 protowire 包,它允许从有线格式的 protobuf 消息中提取有限的信息。请记住,protobuf 消息的线路表示不明确,导致语义较弱。
以下代码解析未知的 protobuf 消息:
type Field struct { Tag Tag Val Val } type Tag struct { Num int32 Type protowire.Type } type Val struct { Payload interface{} Length int } func parseUnknown(b []byte) []Field { // ... implementation to parse unknown protobuf messages as described in the provided answer ... }
给定一个 protobuf 模式像:
message Foo { string a = 1; string b = 2; Bar bar = 3; } message Bar { string c = 1; }
以下代码演示了如何使用解析器:
// Parse the protobuf message as byte slice b := []byte{0x0a, 0x01, 0x41, 0x12, 0x01, 0x42, 0x1a, 0x03, 0x43} fields := parseUnknown(b) for _, field := range fields { fmt.Printf("%#v\n", field) }
输出:
main.Field{Tag:main.Tag{Num:1, Type:2}, Val:main.Val{Payload:[]uint8{0x41}, Length:1}} main.Field{Tag:main.Tag{Num:2, Type:2}, Val:main.Val{Payload:[]uint8{0x42}, Length:1}} main.Field{Tag:main.Tag{Num:1, Type:2}, Val:main.Val{Payload:[]uint8{0x43}, Length:1}} main.Field{Tag:main.Tag{Num:3, Type:2}, Val:main.Val{Payload:[]main.Field{main.Field{Tag:main.Tag{Num:1, Type:2}, Val:main.Val{Payload:[]uint8{0x43}, Length:1}}}, Length:3}}
以上是如何在 Go 中解组未知的 Protobuf 消息?的详细内容。更多信息请关注PHP中文网其他相关文章!