Question

j'utilise cgo pour développer la liaison de bibliothèque à partir de Go.Permettez-moi de considérer la structure C et Go Struct comme ci-dessous.

struct cons_t {
  size_t type;
  cons_t *car;
  cons_t *cdr;
};

cons_t* parse(const char *str);

et c'est la structure de go

type Cons struct {
  type int;
  car *Cons;
  cdr *Cons;
}

Pour implémenter la fonction Go comme ci-dessous, quelle est la meilleure façon d'implémenter TranslateCCons2GoCons ?

func Parse (str string) *Cons {
  str_ptr := C.CString(string);
  cons_ptr := C.parse(str_ptr);
  retCons := TranslateCCons2GoCons(cons_ptr);
  return retCons;
}

Ma première réponse est la suivante.

/*#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)};
}

existe-t-il un meilleur moyen ?

Était-ce utile?

La solution

Je déconseille les fonctions d'accesseur.Vous devriez pouvoir accéder directement aux champs de la structure C, ce qui évitera la surcharge d'appel de fonction Go -> C (qui n'est pas triviale).Vous pourriez donc utiliser quelque chose comme :

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

De plus, si vous allouez une chaîne C avec C.CString, vous devez le libérer.Alors ton Parse la fonction devrait ressembler à quelque chose comme :

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
}

Autres conseils

Vous pouvez utiliser des structures C dans Go (mais si le struct détient un union ça devient un peu plus complexe).Le plus simple serait simplement

type Cons struct {
    c C.cons_t
}

Toute fonction en C n'est plus qu'un relais dans 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)}
}

Cela a sa propre surcharge, puisque vous devez effectuer une conversion de type lors de l'accès aux éléments.Alors qu'était-ce qu'il y avait avant var c Cons{}; c.Type est maintenant

func (c Cons) Type() int {
    return int(c.c.type)
}

Un compromis intermédiaire peut être utilisé lorsque vous stockez des champs à côté du type C pour un accès facile

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
}

Le seul vrai problème est que si vous appelez beaucoup des fonctions C, cela peut introduire une surcharge de maintenance dans la définition des champs Go-side :

func (c *Cons) SomeFuncThatAltersType() {
    C.someFuncThatAltersType(&c.c)
    c.Type = int(c.c.type) // now we have to remember to do this
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top