Estructuras de Datos Genéricas: Conjuntos, Colas, Mapas
Los genéricos te permiten enviar conjuntos, colas y ayudantes de mapas tipados una vez por módulo en lugar de mantener StringSet, IntSet y la salida de go generate.
Busca en todas las páginas de la documentación
Los genéricos te permiten enviar conjuntos, colas y ayudantes de mapas tipados una vez por módulo en lugar de mantener StringSet, IntSet y la salida de go generate.
Un conjunto genérico suele ser map[T]struct{} con claves comparable.
Las colas envuelven slices con índices de cabeza/cola o usan buffers de anillo para capacidad fija.
Los ayudantes de mapas centralizan la obtención segura de valores predeterminados, la copia y la lógica de transformación con dos parámetros de tipo K y V.
Mantén las API de contenedores exportadas pequeñas y documenta el comportamiento del valor cero.
Tarjeta de referencia rápida - lista para copiar y pegar.
type Set[T comparable] map[T]struct{}
func NewSet[T comparable](vals ...T) Set[T] {
s := make(Set[T], len(vals))
for _, v := range vals {
s.Add(v)
}
return s
}
func (s Set[T]) Add(v T) { s[v] = struct{}{} }
func (s Set[T]) Has(v T) bool { _, ok := s[v]; return ok }Cuándo usar esto:
map[string]struct{} en varios paquetes.interface{}.package main
import (
"fmt"
)
type Set[T comparable] map[T]struct{}
func (s Set[T]) Add(v T) { s[v] = struct{}{} }
func (s Set[T]) Has(v T) bool {
_, ok := s[v]
return ok
}
type Queue[T any] struct {
buf []T
}
func (q *Queue[T]) Enqueue(v T) { q.buf = append(q.buf, v) }
func (q *Queue[T]) Dequeue() (T, bool) {
if len(q.buf) == 0 {
var zero T
return zero, false
}
v := q.buf[0]
q.buf = q.buf[1:]
return v, true
}
func GetOr[K comparable, V any](m map[K]V, k K, def V) V {
if v, ok := m[k]; ok {
return v
}
return def
}
func main() {
s := make(Set[string])
s.Add("go")
fmt.Println(s.Has("go"), s.Has("rust"))
var q Queue[int]
q.Enqueue(1)
q.Enqueue(2)
v, _ := q.Dequeue()
fmt.Println(v)
m := map[string]int{"a": 1}
fmt.Println(GetOr(m, "b", 0))
}Lo que esto demuestra:
Set[T] requiere comparable para las claves del mapa.Queue[T] usa any porque los elementos solo se almacenan y mueven.GetOr separa la comparabilidad de la clave de la flexibilidad del tipo de valor.type Set[T comparable] map[T]struct{}) crean un tipo nombrado distinto por cada instanciación.var q Queue[int] es una cola vacía; make(Set[string]) asigna el mapa.| Estructura | Restricción | Respaldo | Notas |
|---|---|---|---|
| Set | comparable | map[T]struct{} | Los valores de struct vacíos no usan memoria de valor adicional |
| Queue (simple) | any | Slice con re-slicing | Encolamiento O(1) amortizado; dequeue desplaza o copia la cabeza |
| Queue (anillo) | any | []T fijo + índices | Mejor para profundidad máxima conocida |
| Stack | any | Slice | Igual que LIFO append/pop |
| Ayudante de Mapa | K comparable, V any | Mapa del llamador | Sin propiedad - funciones puras |
// Ring queue evita dequeue O(n) del re-slicing de slice a escala
type RingQueue[T any] struct {
buf []T
head int
tail int
n int
}
func NewRingQueue[T any](cap int) *RingQueue[T] {
return &RingQueue[T]{buf: make([]T, cap)}
}sync.Mutex o usa sync.Map cuando las claves sean any y los patrones de contención encajen.MarshalJSON personalizado por instanciación o funciones auxiliares; los mapas se serializan bien cuando las claves son cadenas.container/list solo cuando necesites enlaces intrusivos; los genéricos más los slices cubren la mayoría de las colas de servicio.buf = buf[1:] de slice - Mantiene el array subyacente vivo, filtrando memoria en colas de larga duración. Solución: usa un buffer de anillo o copia periódica cuando len << cap.Set[T] es un mapa nil; las escrituras provocan pánico. Solución: make(Set[T]) o un constructor.map[uint64]struct{}.map[K]*V copian punteros, no los datos a los que apuntan. Solución: documenta semántica superficial o clona valores.
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
go generate por tipo | Máximo control, sin sintaxis de corchetes en la API | Pocos tipos, el equipo prefiere genéricos |
Solo map[string]struct{} | Conjunto único de cadenas | Múltiples tipos de elementos |
container/heap | Semántica de cola de prioridad | FIFO simple |
| Cola de buffer de canal | Transferencia de goroutines | Batching en un solo hilo |
Los valores de struct vacíos no ocupan bytes.
La membresía es O(1) en promedio con buenas propiedades de hash en T.
A menudo se mantienen las colas internas.
Exporta el comportamiento (procesador de lotes), no los tipos Queue[T], a menos que la biblioteca sea un kit de estructuras de datos.
for k := range s en el patrón del mapa subyacente.
Añade un método Values() que devuelva []T si los llamadores necesitan slices.
No - los mapas estándar no son seguros para escrituras concurrentes.
Añade un envoltorio de mutex o usa mapas concurrentes.
Convierte a []T para marshaling.
map[T]struct{} no se marshala a JSON como un array por defecto.
Los canales sincronizan goroutines.
Las colas genéricas se adaptan al batching en memoria dentro de una goroutine o con bloqueo externo.
K comparable y V any cubren la mayoría de los ayudantes.
Añade un tercer parámetro solo para pipelines de transformación.
No para valores comparables pequeños.
Usa punteros como elementos cuando los valores sean grandes y la identidad importe.
Usa un mapa más una caché de slice ordenada, o estructuras tree de paquetes de terceros.
Los genéricos no implican ordenación.
Decenas de instanciaciones en objetivos embebidos pequeños donde el tamaño binario domina.
Mide antes de elegir.
Sí - compone Set[T] dentro de tipos estilo Graph[N comparable].
Vigila el tiempo de compilación y el tamaño binario.
Pruebas de tabla con múltiples instanciaciones (Set[int], Set[string]) en el mismo archivo de prueba del paquete.
Versiones de Stack: Esta página fue escrita para Go 1.26.x (predeterminado GC de Green Tea, go fix modernizers - verifica el parche en la compilación), chi (última - verifica en la compilación), gin (última - verifica en la compilación), echo (última - verifica en la compilación), google.golang.org/grpc (última - verifica en la compilación), sigs.k8s.io/controller-runtime (última - verifica en la compilación), kubebuilder (última - verifica en la compilación), tinygo (última - verifica objetivos de placa en la compilación), wazero (última - verifica en la compilación) y golangci-lint (última - verifica el conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 19 jul 2026