سؤال

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.

هل كانت مفيدة؟

المحلول 2

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

نصائح أخرى

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)
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top