【问题标题】:Golang (cgo) - Arbitrary void* interfaceGolang (cgo) - 任意 void* 接口
【发布时间】:2013-02-26 16:33:03
【问题描述】:

我正在包装一个 C 库,该库具有一个带有 void* 数据字段的结构,可用于任意保存数据。将其包装在惯用的 Go 中的最佳方式(如果可能的话)是什么?

结构很简单:

typedef struct _Foo {
    void * data;
} Foo;

我希望做类似的事情:

type Foo C.Foo

func (f *Foo) SetData(data interface{}) {
    f.data = unsafe.Pointer(&data)
}

func (f *Foo) Data() interface{} {
    return (interface{})(unsafe.Pointer(f.data))
}

这不起作用,而且显然是错误的方法。

我已经使用 []byte 源成功地设置了一个带有长度字段的 void* 数据,但是这个无长度接口让我无法理解。

【问题讨论】:

  • 对于好奇的人来说,最终目标是这个 - github.com/boj/goenet - 虽然还是有点问题,所以要小心。

标签: go cgo


【解决方案1】:

如果您获取interface 的地址,则您获取的是值类型的地址(大致为struct { tInfo *typeInfo, payload uintPtr}),而不是接口“装箱”的数据。如果有效负载字段适合机器字,则它们可以保存真实数据,否则该字段保存指向实际有效负载的指针。但这些是实施细节,不应直接与 IMO 合作。

我会使用非通用的,例如(未经测试的代码,仅架构):

func (f *Foo) SetT(p *T) {
        (*C.Foo)(f).data = unsafe.Pointer(p)
}

func (f *Foo) GetT() *T {
        return (*T)((*C.Foo)(f).data)
}

【讨论】:

  • 是的,这就是我发布问题后一直在考虑的问题。
  • 您也可以使用reflect.Elem()reflect.Pointer() 来获取接口包含的值的uintptr
  • reflect.func (Value) Pointer: “如果 v 的 Kind 不是 Chan、Func、Map、Ptr、Slice 或 UnsafePointer,它会发生混乱。”
【解决方案2】:

在我使用 Go 的几个月后回到这个问题,我想出了以下(更新,感谢 zupa)解决方案。

func (f *Foo) SetData(data interface{}) {
    f.data = unsafe.Pointer(&data)
}

func (f *Foo) Data() interface{} {
    return unsafe.Pointer(f.data)
}

并且可以通过以下方式使用:

type Player struct {
    Name string
}

p := &Player{
    Name: "Player1",
}

f.SetData(p)

log.Print(f.Data().(*Player).Name) // Outputs: Player1

【讨论】:

  • 为什么要把数据存储在&FooData{}
  • 不久前我正在包装 ENet 库。您不需要在数据字段中存储任何内容,但它是作为客户端库将 Peer 连接到诸如 Player 之类的游戏内构造的一种机制 - enet.bespin.org/…
  • 抱歉,我的问题不清楚。我不是在问你为什么要存储数据。我在问你为什么将data 包裹在&FooData{} 中而不是直接使用f.data = unsafe.Pointer(&data)
  • 啊,我明白了。老实说,我不记得为什么它最终会变得如此复杂。用正确的代码编辑了答案。
  • 好的,干杯!对于任何阅读本文的人,我问自己阅读 sn-p GC 是否会释放 unsafe.Pointer 指向的任何内容。不,不会的。 Explained here
猜你喜欢
  • 2014-05-25
  • 2019-07-19
  • 2013-09-22
  • 2014-08-28
  • 1970-01-01
  • 2019-08-11
  • 2018-09-28
  • 1970-01-01
  • 2020-12-04
相关资源
最近更新 更多