Genere implementaciones para tipos genéricos en Go

Go tiene tipos fuertes y estáticos y no admite genéricos, entonces, ¿cómo podemos definir estructuras de datos de propósito general y algoritmos que se puedan aplicar a más de un tipo?interface{}s no son la solución, ya que requieren conversión y perdemos muchas de las ventajas de tener una escritura fuerte y estática.La solución es la generación de código., ya que permite obtener comprobaciones y seguridad en tiempo de compilación y un mayor rendimiento.

No encontré esta información de fácil acceso cuando buscaba temas de generación de código, pero encontré casos de uso y escenarios más complejos, así que aquí está, explicado en un lenguaje sencillo.

Problema:

quieroimplementar una estructura de datos(lo mismo se aplica a un algoritmo)de la manera más general posiblecon Go, ygenerar implementaciones específicas de tipo que puedo reutilizar fácilmente.

Solución:

Usandogenny, esto no podría ser más simple:

  1. importargenny/generic
  2. definir uno o más tipos comogeneric.Type, por ejemplo, llamándolosItemoType
  3. usa estos tipos en tu código
  4. corrergennypara generar la implementación específica del tipo

Ejemplo

Consulte este sencillo ejemplo, que es una versión recortada de unEstablecer la implementación de la estructura de datos en Go:

// Package set creates a ItemSet data structure for the Item type
package set

import github.com/cheekybits/genny/generic

// Item the type of the Set type Item generic.Type

// ItemSet the set of Items type ItemSet struct { items map[Item]bool }

// Add adds a new element to the Set. Returns the Set. func (s ItemSet) Add(t Item) ItemSet { if s.items == nil { s.items = make(map[Item]bool) } _, ok := s.items[t] if !ok { s.items[t] = true } return s }

// Clear removes all elements from the Set func (s ItemSet) Clear() { (s).items = make(map[Item]bool) }

Mediante la ejecución

genny -in set.go -out gen-set.go gen "Item=string,int"

en la línea de comando ahora, si el archivo se llamaset.gogenerará ungen-set.goque contiene lo siguiente:

// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny

// Package Set creates a StringSet data structure for the string type
package set

// StringSet the set of Strings type StringSet struct { items map[string]bool }

// Add adds a new element to the Set. Returns the Set. func (s StringSet) Add(t string) StringSet { s.items[t] = true return s }

// Clear removes all elements from the Set func (s StringSet) Clear() { (s).items = make(map[string]bool) }

// Delete removes the string from the Set and returns Has(string) func (s StringSet) Delete(item string) bool { ret := (s).Has(item) if ret { delete((*s).items, item) } return ret }

// Has returns true if the Set contains the string func (s StringSet) Has(item string) bool { return (s).items[item] }

// Strings returns the string(s) stored func (s *StringSet) Strings() []string { items := []string{} for i := range s.items { items = append(items, i) } return items }

// Package Set creates a IntSet data structure for the int type // IntSet the set of Ints type IntSet struct { items map[int]bool }

// Add adds a new element to the Set. Returns the Set. func (s IntSet) Add(t int) IntSet { s.items[t] = true return s }

// Clear removes all elements from the Set func (s IntSet) Clear() { (s).items = make(map[int]bool) }

// Delete removes the int from the Set and returns Has(int) func (s IntSet) Delete(item int) bool { ret := (s).Has(item) if ret { delete((*s).items, item) } return ret }

// Has returns true if the Set contains the int func (s IntSet) Has(item int) bool { return (s).items[item] }

// Ints returns the int(s) stored func (s *IntSet) Ints() []int { items := []int{} for i := range s.items { items = append(items, i) } return items }

Como se puede ver,gennyha creado elStringSetyIntSetestructuras deItemSet**, porque lo dijeItem=string,int.

También creó los métodos de estructuraque componen nuestras implementaciones de Set.

Si queremos agregar otro conjunto de tipos a nuestra aplicación podemos editar el comando y ejecutarlo nuevamente.

Usargo generate

También puede automatizar esto agregando un comentario en la parte superior del archivo, debajo del documento del paquete, como:

// go:generate genny -in=$GOFILE -out=gen-$GOFILE gen "Item=string,int"

Esto dicego generate, con la ayuda degenny, para generar una versión traduciendoItemastringy una segunda versión que traduceitemaint.

Correr

go generate

para obtener elgen-set.goarchivo, con conjuntos de cadenas e int.

Pruebas

Importante: la implementación genérica de la estructura de datos anteriorcompila y se puede probartan fácilmente como una implementación concreta generada porgo generate, por lo que podemos ejecutar pruebas con nuestra implementación genérica, así como con las específicas del tipo.


Más tutoriales de go: