将盒装结构转换为盒装指针 - golang



我正在使用Protobuf作为Golang。Protobuf 生成消息类型,其中类型指针实现proto.Message() 。例如

func (*SomeMessage) Message() {}

protobuf lib 有类似 Marshal(proto.Message)

现在谈谈我的实际问题。

message := SomeMessage {}
SendMessage(&message)
func SendMessage(message interface{}) {
   switch msg := message.(type) {
      case proto.Message:
          //send across the wire or whatever
      default:
          //non proto message, panic or whatever
   }
}

以上工作正常。但是,如果我不将消息作为指针传递,则 SendMessage 中的代码将不匹配,因为接口仅在 SomeMessage 指针上实现,而不是在值上实现。

我想做的是:

message := SomeMessage {}
SendMessage(message) //pass by value
//there are more stuff going on in my real code, but just trying to show the relevant parts
func SendMessage(message interface{}) {
   //match both pointer and value as proto.Message
   //and then turn the value into a pointer so that
   //other funcs or protobuf can consume it   
   message = MagicallyTurnBoxedValueIntoBoxedStruct(message)       
   switch msg := message.(type) {
      case proto.Message:
          //send across the wire or whatever
      default:
          //non proto message, panic or whatever
   }
}

最好我希望能够同时作为指针和值传递。我想按值传递的原因是,当跨 goroutines/线程等传递消息时,这可以充当穷人的隔离。(缺乏不变性)

如果 protobuf 生成器生成的值也允许被视为proto.Message(),则所有这些可能都可以避免。或者,如果有一些更好的方法来执行不可变的消息。

这不是超级重要,如果可能的话,很酷,如果不是,嗯:-)

[编辑]

如果我有反射。消息和反射的类型。消息的指针类型的类型。是否可以以某种方式使用"reflect"创建指向值的指针类型的实例?

通常,你不能获取值的地址,这意味着你不能简单地将接口{}转换为指针来满足Protobuf的要求。

也就是说,您可以动态创建一个新指针,然后将值复制到该指针中,然后将新分配的指针传递给 protobuf。

这是播放的示例

指针转换的值 ->为:

func mkPointer(i interface{}) interface{} {
    val := reflect.ValueOf(i)
    if val.Kind() == reflect.Ptr {
        return i
    }
    if val.CanAddr() {
        return val.Addr().Interface()
    }
    nv := reflect.New(reflect.TypeOf(i))
    nv.Elem().Set(val)
    return nv.Interface()
}
  • 我们首先看看它是否是一个指针,如果是,只需返回值。
  • 然后我们检查它是否可寻址并返回。
  • 最后,我们创建一个类型的新实例,并将内容复制到该实例并返回它。

由于这会复制数据,因此可能不适合您的目的。 这完全取决于消息的大小和具有值的预期调用速率(因为这将产生更多的垃圾)。

最新更新