Modo buono o consigliato per tradurre la struttura c per andare a strutture

StackOverflow https://stackoverflow.com//questions/23004474

  •  20-12-2019
  •  | 
  •  

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?

È stato utile?

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top