Manera buena o recomendada de traducir la estructura C a la estructura Go

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

  •  20-12-2019
  •  | 
  •  

Pregunta

Estoy usando cgo para desarrollar enlaces de bibliotecas desde Go.Permítanme considerar la estructura C y la estructura Go como se muestra a continuación.

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

cons_t* parse(const char *str);

y esta es la estructura de go

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

Para implementar la función Go como se muestra a continuación, ¿cuál es la mejor manera de implementar TranslateCCons2GoCons?

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

Mi primera respuesta es la siguiente.

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

¿Hay alguna manera mejor?

¿Fue útil?

Solución

Recomendaría no utilizar las funciones de acceso.Debería poder acceder a los campos de la estructura C directamente, lo que evitará la sobrecarga de llamada a la función Ir -> C (que no es trivial).Entonces podrías usar algo como:

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

Además, si asigna una cadena C con C.CString, necesitas liberarlo.Entonces tus Parse La función debería verse así:

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
}

Otros consejos

Puedes usar estructuras C en Go (aunque si el struct sostiene un union se vuelve un poco más complejo).La forma más sencilla sería simplemente

type Cons struct {
    c C.cons_t
}

Cualquier función en C ahora es solo un paso en 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)}
}

Esto tiene sus propios gastos generales, ya que debe realizar una conversión de tipo al acceder al elemento.Entonces, ¿qué fue antes? var c Cons{}; c.Type es ahora

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

Se puede utilizar un compromiso intermedio donde se almacenan campos junto con el tipo C para facilitar el acceso.

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
}

El único problema real con esto es que si llamas muchas funciones de C, esto puede generar una sobrecarga de mantenimiento al configurar los campos del lado Go:

func (c *Cons) SomeFuncThatAltersType() {
    C.someFuncThatAltersType(&c.c)
    c.Type = int(c.c.type) // now we have to remember to do this
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top