Protocol Buffers任意类型

245 阅读2分钟

在使用pb的时候, 在微服务中有一些数据是要透传的, 比如A服务调用B服务, 返回的数据有一些字段A服务是不关心内容的, 只需要原样传给客户端, 如果使用具体的类型, 每次B服务修改message的时候, A服务也要跟着编译,不利于开发, 那怎么办, 这时候就要用到Any类型.

Q: protocol buffers 有没有一种类型, 可以存放任意的类型

A: Protocol Buffers 提供了一种可以存放任意类型的字段,这就是 google.protobuf.Any 类型。这个类型允许你在不知道具体类型的情况下序列化和反序列化任意的 Protocol Buffers 消息。以下是 Any 类型的主要特点和使用方法:

  1. 定义:

在 .proto 文件中,你需要导入 google/protobuf/any.proto,然后就可以使用 Any 类型了。

   import "google/protobuf/any.proto";

   message Container {
     google.protobuf.Any data = 1;
   }
  1. 序列化:

在 Go 中,你可以使用 anypb.New() 函数将任何实现了 proto.Message 接口的类型封装到 Any 中。

   import (
     "google.golang.org/protobuf/types/known/anypb"
     "google.golang.org/protobuf/proto"
   )

   someMessage := &MyMessage{...}
   anyMessage, err := anypb.New(someMessage)
  1. 反序列化:

要从 Any 中提取具体类型,你需要知道原始消息的类型,然后使用 anypb.UnmarshalNew() 函数。

   var myMessage MyMessage
   err := anyMessage.UnmarshalTo(&myMessage)

4.类型检查:

Any 类型包含一个 type_url 字段,可以用来识别封装的消息类型

   if anyMessage.MessageIs(&MyMessage{}) {
     // 处理 MyMessage 类型
   }
  1. 注意事项:
  • 使用 Any 类型会增加一些运行时开销,因为它需要额外的序列化和反序列化步骤。

  • 在反序列化时,你需要知道或者能够推断出原始消息的类型。

  • Any 类型主要用于那些无法在编译时确定具体类型的场景。

  1. 替代方案: 如果你知道可能的类型集合,使用 oneof 字段可能是更好的选择,因为它更类型安全且效率更高。
message Container {
     oneof data {
       StringMessage string_message = 1;
       IntMessage int_message = 2;
       // 其他可能的类型...
     }
   }