我正在使用Protobuf for Golang。
Protobuf生成类型指针实现proto.Message()
的消息类型。
e.g。
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 / threads等之间传递消息时,这可以作为一个糟糕的勒芒隔离。 (缺乏不变性)
如果protobuf生成器生成的允许值也被视为proto.Message()
,则可以避免所有这些。
或者,如果有一些更好的方法来做不可变的消息。
这不是非常重要,如果可能的话,很酷,如果不是,请注意: - )
[编辑]
如果我有消息的reflect.Type和消息的指针类型的reflect.Type。 是否有可能使用“reflect”创建指向该值的指针类型的实例?
答案 0 :(得分:1)
通常情况下,您无法获取值的地址,这意味着您无法简单地将接口{}转换为满足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()
}
由于这会复制数据,因此可能不适用于您的目的。它将全部取决于消息的大小和预期的调用率(因为这将产生更多的垃圾)。