Modo buono o consigliato per tradurre la struttura c per andare a strutture
Domanda
Sto usando CGO per lo sviluppo della biblioteca vincolante da GO. Fammi prendere in considerazione la struttura c e andare struct come di seguito.
struct cons_t {
size_t type;
cons_t *car;
cons_t *cdr;
};
cons_t* parse(const char *str);
.
E questo è la struttura di go è
type Cons struct {
type int;
car *Cons;
cdr *Cons;
}
.
Per l'implementazione della funzione Vai come di seguito, qual è il modo migliore per implementare TranslateCons2Gocons?
func Parse (str string) *Cons {
str_ptr := C.CString(string);
cons_ptr := C.parse(str_ptr);
retCons := TranslateCCons2GoCons(cons_ptr);
return retCons;
}
.
La mia prima risposta è di seguito.
/*#cgo
int getType(cons_t *cons) {
return cons->type;
}
cons_t *getCar(cons_t *cons) {
return cons->car;
}
cons_t *getCdr(cons_t *cons) {
return cons->cdr;
}
*/
func TranslateCCons2GoCons (c *C.cons_t) Cons {
type := C.getType(c);
car := C.getCar(c);
cdr := C.getCdr(c);
// drop null termination for simplicity
return Cons{type, TranslateCCons2GoCons(car), TranslateCCons2GoCons(cdr)};
}
.
Ci sono dei modi migliori?
Soluzione
Consiglierei contro le funzioni Accessor.Dovresti essere in grado di accedere direttamente ai campi della struttura C, che eviterà il sovraccarico di chiamata Vai -> c (che non è banale).Quindi potresti usare qualcosa come:
func TranslateCCons2GoCons (c *C.cons_t) *Cons {
if c == nil {
return nil
}
return &Cons{
type: int(c.type),
car: TranslateCCons2GoCons(c.car),
cdr: TranslateCCons2GoCons(c.cdr),
}
}
.
Inoltre, se si assegna una stringa C con C.CString
, è necessario liberarlo.Quindi la tua funzione Parse
dovrebbe apparire come:
func Parse (str string) *Cons {
str_ptr := C.CString(str)
defer C.free(unsafe.Pointer(str_ptr)
cons_ptr := C.parse(str_ptr)
retCons := TranslateCCons2GoCons(cons_ptr)
// FIXME: Do something to free cons_ptr here. The Go runtime won't do it for you
return retCons
}
. Altri suggerimenti
È possibile utilizzare C striscia in GO (anche se il struct
contiene un union
è un po 'più complesso).Il modo più semplice sarebbe solo
type Cons struct {
c C.cons_t
}
.
Qualsiasi funzione in c è ora solo una passthrough in go
func Parse(s string) Cons {
str := C.CString(s)
// Warning: don't free this if this is stored in the C code
defer C.free(unsafe.Pointer(str))
return Cons{c: C.parse(str)}
}
.
Questo ha il suo sovraccarico, dal momento che devi eseguire una conversione di tipo sull'accesso degli elementi.Allora, cosa prima che var c Cons{}; c.Type
è ora
func (c Cons) Type() int {
return int(c.c.type)
}
.
Un compromesso intermedio può essere utilizzato in cui si memorizzano campi accanto al tipo C per un facile accesso
type Cons struct {
type int
c C.cons_t
}
func (c *Cons) SetType(t int) {
c.type = t
c.c.type = C.size_t(t)
}
func (c Cons) Type() int {
return c.type
}
.
L'unico problema reale con questo è che se stai chiamando molto le funzioni C, questo può introdurre il sovraccarico di manutenzione nell'impostazione dei campi Vai -
func (c *Cons) SomeFuncThatAltersType() {
C.someFuncThatAltersType(&c.c)
c.Type = int(c.c.type) // now we have to remember to do this
}
.