Golang(cgo)- 任意的void*接口

huangapple go评论76阅读模式
英文:

Golang (cgo) - Arbitrary void* interface

问题

我正在封装一个包含一个void*数据字段的C库的结构体,该字段可以用于任意保存数据。如果可能的话,最好的方法是什么,以符合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*数据,但是这种没有长度的接口让我困扰。

英文:

I am wrapping a C library that has a struct with a void* data field that can be used to arbitrarily hold data. What would be the best way (if it's even possible) to wrap this in idiomatic Go?

The struct is quite simply:

typedef struct _Foo {
    void * data;
} Foo;

I was hoping to do something like:

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))
}

This doesn't work, and is clearly the wrong approach anyways.

I have successfully set a void* data with a length field using a []byte source, but this length-less interface eludes me.

答案1

得分: 3

如果您获取一个interface的地址,您获取的是一个值类型的地址(大致为struct { tInfo *typeInfo, payload uintPtr}),而不是由该接口“装箱”的数据。如果数据适合一个机器字,那么payload字段可以保存真实的数据,否则该字段保存指向实际数据的指针。但这些是实现细节,不应直接使用,我个人认为。

我会选择非泛型的方式,如下所示(未经测试的代码,仅为示意):

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

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

if you take an adres of an interface, you're taking address of a value type (roughly struct { tInfo *typeInfo, payload uintPtr}), not the data "boxed" by the interface. The payload field can hold the real data if they fit into a machne word, otherwise that field holds a pointer to the actual payload. But these are implementation details and should not be worked directly with, IMO.

I would go non generic, like (untested code, schema only):

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

and

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

答案2

得分: 2

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) // 输出: Player1

英文:

Coming back to this after several more months of Go under my belt I came up with the following (updated, thanks zupa) solution.

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

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

And can be used in the following manner:

type Player struct {
    Name string
}

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

f.SetData(p)

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

huangapple
  • 本文由 发表于 2013年3月11日 21:16:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/15339603.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定