【问题标题】:Cast boxed struct to boxed pointer - golang将盒装结构转换为盒装指针 - golang
【发布时间】:2016-04-26 12:04:41
【问题描述】:

我正在为 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。 是否有可能使用“反射”创建指向值的指针类型的实例?

【问题讨论】:

    标签: go protocol-buffers


    【解决方案1】:

    通常,您不能获取值的地址,这意味着您不能简单地将 interface{} 转换为指针以满足 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()
    }
    
    • 我们先看看是不是指针,如果是,直接返回值。
    • 然后我们检查它是否可寻址并返回。
    • 最后,我们创建一个该类型的新实例并将内容复制到该实例并返回它。

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

    【讨论】:

    • @RogerAlsing 我想指出的是,虽然这很有效,但它会非常缓慢且过度设计,不应该在任何实际项目中使用。
    • 是的,我明白了,最好的解决方案是让 protoc 生成不可变结构.. 但看到它是可能的仍然很有趣。
    猜你喜欢
    • 2015-01-26
    • 1970-01-01
    • 1970-01-01
    • 2015-04-30
    • 2018-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-27
    相关资源
    最近更新 更多