将盒装结构投射到盒装指针 - golang
Cast boxed struct to boxed pointer - golang
我正在为 Golang 使用 Protobuf。
Protobuf 生成类型指针实现 proto.Message()
的消息类型。
例如
func (*SomeMessage) Message() {}
protobuf 库有类似 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" 创建指向该值的指针类型的实例?
通常情况下,你不能获取值的地址,这意味着你不能简单地将接口{}转换为指针来满足 Protobuf 的要求。
也就是说,您可以动态创建一个新指针,然后将值复制到其中,然后将新分配的指针传递给 protobuf。
这是一个example on Play
值->指针转换为:
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()
}
- 我们先看是不是指针,如果是,就return这个值。
- 然后我们检查它是否可寻址,return。
- 最后,我们创建该类型的一个新实例并将内容复制到其中 return。
由于这是复制数据,因此对于您的目的可能不实用。这将完全取决于消息的大小和使用值调用的预期速率(因为这会产生更多垃圾)。
我正在为 Golang 使用 Protobuf。
Protobuf 生成类型指针实现 proto.Message()
的消息类型。
例如
func (*SomeMessage) Message() {}
protobuf 库有类似 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" 创建指向该值的指针类型的实例?
通常情况下,你不能获取值的地址,这意味着你不能简单地将接口{}转换为指针来满足 Protobuf 的要求。
也就是说,您可以动态创建一个新指针,然后将值复制到其中,然后将新分配的指针传递给 protobuf。
这是一个example on Play
值->指针转换为:
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()
}
- 我们先看是不是指针,如果是,就return这个值。
- 然后我们检查它是否可寻址,return。
- 最后,我们创建该类型的一个新实例并将内容复制到其中 return。
由于这是复制数据,因此对于您的目的可能不实用。这将完全取决于消息的大小和使用值调用的预期速率(因为这会产生更多垃圾)。